]>
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 | |
5ae82640 | 229 | /* apply/restore inotify watch */ |
3d3a0a70 | 230 | if (err == 0 && event->inotify_watch) { |
5ae82640 | 231 | udev_watch_begin(event->udev, event->dev); |
3d3a0a70 KS |
232 | udev_device_update_db(event->dev); |
233 | } | |
5ae82640 | 234 | |
cb25a958 | 235 | info(event->udev, "seq %llu exit with %i\n", udev_device_get_seqnum(event->dev), err); |
c895fd00 | 236 | logging_close(); |
aa8734ff | 237 | if (err != 0) |
f4fc0136 | 238 | exit(1); |
c895fd00 | 239 | exit(0); |
90c210eb | 240 | case -1: |
aa8734ff KS |
241 | err(event->udev, "fork of child failed: %m\n"); |
242 | event_queue_delete(event); | |
2f6cbd19 | 243 | break; |
90c210eb | 244 | default: |
2f6cbd19 | 245 | /* get SIGCHLD in main loop */ |
aa8734ff KS |
246 | info(event->udev, "seq %llu forked, pid [%d], '%s' '%s', %ld seconds old\n", |
247 | udev_device_get_seqnum(event->dev), | |
248 | pid, | |
249 | udev_device_get_action(event->dev), | |
250 | udev_device_get_subsystem(event->dev), | |
251 | time(NULL) - event->queue_time); | |
252 | event->pid = pid; | |
0bc74ea7 | 253 | childs++; |
90c210eb | 254 | } |
7fafc032 KS |
255 | } |
256 | ||
aa8734ff | 257 | static void event_queue_insert(struct udev_event *event) |
fc465079 | 258 | { |
17fcfb59 | 259 | char filename[UTIL_PATH_SIZE]; |
7baada47 KS |
260 | int fd; |
261 | ||
aa8734ff | 262 | event->queue_time = time(NULL); |
7baada47 | 263 | |
aa8734ff | 264 | export_event_state(event, EVENT_QUEUED); |
cb25a958 KS |
265 | info(event->udev, "seq %llu queued, '%s' '%s'\n", udev_device_get_seqnum(event->dev), |
266 | udev_device_get_action(event->dev), udev_device_get_subsystem(event->dev)); | |
0f624f16 | 267 | |
aa8734ff | 268 | util_strlcpy(filename, udev_get_dev_path(event->udev), sizeof(filename)); |
31c1f537 | 269 | util_strlcat(filename, "/.udev/uevent_seqnum", sizeof(filename)); |
7baada47 | 270 | fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0644); |
90cd961e | 271 | if (fd >= 0) { |
7baada47 KS |
272 | char str[32]; |
273 | int len; | |
274 | ||
aa8734ff | 275 | len = sprintf(str, "%llu\n", udev_device_get_seqnum(event->dev)); |
7baada47 KS |
276 | write(fd, str, len); |
277 | close(fd); | |
278 | } | |
fc465079 | 279 | |
0bc74ea7 KS |
280 | |
281 | udev_list_node_append(&event->node, &event_list); | |
282 | run_exec_q = 1; | |
c7c00276 | 283 | |
fc465079 | 284 | /* run all events with a timeout set immediately */ |
aa8734ff | 285 | if (udev_device_get_timeout(event->dev) > 0) { |
aa8734ff | 286 | event_fork(event); |
fc465079 KS |
287 | return; |
288 | } | |
fc465079 KS |
289 | } |
290 | ||
f051e340 KS |
291 | static int mem_size_mb(void) |
292 | { | |
9f1f67b1 KS |
293 | FILE* f; |
294 | char buf[4096]; | |
295 | long int memsize = -1; | |
f051e340 | 296 | |
9f1f67b1 KS |
297 | f = fopen("/proc/meminfo", "r"); |
298 | if (f == NULL) | |
f051e340 | 299 | return -1; |
f051e340 | 300 | |
9f1f67b1 KS |
301 | while (fgets(buf, sizeof(buf), f) != NULL) { |
302 | long int value; | |
f051e340 | 303 | |
9f1f67b1 KS |
304 | if (sscanf(buf, "MemTotal: %ld kB", &value) == 1) { |
305 | memsize = value / 1024; | |
306 | break; | |
307 | } | |
308 | } | |
f051e340 | 309 | |
fdc9a0b5 | 310 | fclose(f); |
9f1f67b1 | 311 | return memsize; |
f051e340 KS |
312 | } |
313 | ||
7b6571a9 KS |
314 | static int compare_devpath(const char *running, const char *waiting) |
315 | { | |
e25fa4fa | 316 | int i = 0; |
7b6571a9 | 317 | |
0bc74ea7 | 318 | while (running[i] != '\0' && running[i] == waiting[i]) |
e25fa4fa | 319 | i++; |
7b6571a9 | 320 | |
e25fa4fa AJ |
321 | /* identical device event found */ |
322 | if (running[i] == '\0' && waiting[i] == '\0') | |
323 | return 1; | |
7b6571a9 | 324 | |
e25fa4fa AJ |
325 | /* parent device event found */ |
326 | if (running[i] == '\0' && waiting[i] == '/') | |
327 | return 2; | |
7b6571a9 | 328 | |
e25fa4fa AJ |
329 | /* child device event found */ |
330 | if (running[i] == '/' && waiting[i] == '\0') | |
331 | return 3; | |
7b6571a9 | 332 | |
e25fa4fa | 333 | /* no matching event */ |
7b6571a9 KS |
334 | return 0; |
335 | } | |
336 | ||
fc630eda | 337 | /* lookup event for identical, parent, child, or physical device */ |
0bc74ea7 | 338 | static int devpath_busy(struct udev_event *event) |
7fafc032 | 339 | { |
7e027927 | 340 | struct udev_list_node *loop; |
7b6571a9 | 341 | |
0bc74ea7 KS |
342 | if (event->delaying_seqnum > 0) { |
343 | } | |
344 | /* check if queue contains events we depend on */ | |
345 | udev_list_node_foreach(loop, &event_list) { | |
7e027927 KS |
346 | struct udev_event *loop_event = node_to_event(loop); |
347 | ||
0bc74ea7 KS |
348 | /* we already found a later event, earlier can not block us, no need to check again */ |
349 | if (udev_device_get_seqnum(loop_event->dev) < event->delaying_seqnum) | |
350 | continue; | |
351 | ||
352 | /* event we checked earlier still exists, no need to check again */ | |
353 | if (udev_device_get_seqnum(loop_event->dev) == event->delaying_seqnum) | |
354 | return 2; | |
355 | ||
356 | /* found ourself, no later event can block us */ | |
aa8734ff | 357 | if (udev_device_get_seqnum(loop_event->dev) >= udev_device_get_seqnum(event->dev)) |
fc630eda KS |
358 | break; |
359 | ||
a2f2270e | 360 | /* check our old name */ |
aa8734ff | 361 | if (udev_device_get_devpath_old(event->dev) != NULL) |
0bc74ea7 KS |
362 | if (strcmp(udev_device_get_devpath(loop_event->dev), udev_device_get_devpath_old(event->dev)) == 0) { |
363 | event->delaying_seqnum = udev_device_get_seqnum(loop_event->dev); | |
364 | return 3; | |
365 | } | |
a2f2270e | 366 | |
fc630eda | 367 | /* check identical, parent, or child device event */ |
aa8734ff KS |
368 | if (compare_devpath(udev_device_get_devpath(loop_event->dev), udev_device_get_devpath(event->dev)) != 0) { |
369 | dbg(event->udev, "%llu, device event still pending %llu (%s)\n", | |
370 | udev_device_get_seqnum(event->dev), | |
371 | udev_device_get_seqnum(loop_event->dev), | |
372 | udev_device_get_devpath(loop_event->dev)); | |
0bc74ea7 | 373 | event->delaying_seqnum = udev_device_get_seqnum(loop_event->dev); |
c3b145a3 MK |
374 | return 4; |
375 | } | |
376 | ||
c3b145a3 | 377 | /* check for our major:minor number */ |
aa8734ff KS |
378 | if (major(udev_device_get_devnum(event->dev)) > 0 && |
379 | udev_device_get_devnum(loop_event->dev) == udev_device_get_devnum(event->dev) && | |
380 | strcmp(udev_device_get_subsystem(event->dev), udev_device_get_subsystem(loop_event->dev)) == 0) { | |
381 | dbg(event->udev, "%llu, device event still pending %llu (%d:%d)\n", | |
382 | udev_device_get_seqnum(event->dev), | |
383 | udev_device_get_seqnum(loop_event->dev), | |
384 | major(udev_device_get_devnum(loop_event->dev)), minor(udev_device_get_devnum(loop_event->dev))); | |
0bc74ea7 KS |
385 | event->delaying_seqnum = udev_device_get_seqnum(loop_event->dev); |
386 | return 5; | |
c3b145a3 MK |
387 | } |
388 | ||
fc630eda | 389 | /* check physical device event (special case of parent) */ |
aa8734ff KS |
390 | if (udev_device_get_physdevpath(event->dev) != NULL && |
391 | strcmp(udev_device_get_action(event->dev), "add") == 0) | |
392 | if (compare_devpath(udev_device_get_devpath(loop_event->dev), | |
393 | udev_device_get_physdevpath(event->dev)) != 0) { | |
394 | dbg(event->udev, "%llu, physical device event still pending %llu (%s)\n", | |
395 | udev_device_get_seqnum(event->dev), | |
396 | udev_device_get_seqnum(loop_event->dev), | |
397 | udev_device_get_devpath(loop_event->dev)); | |
0bc74ea7 KS |
398 | event->delaying_seqnum = udev_device_get_seqnum(loop_event->dev); |
399 | return 6; | |
a15f42c4 | 400 | } |
80513ea3 | 401 | } |
a15f42c4 | 402 | return 0; |
7fafc032 KS |
403 | } |
404 | ||
fc630eda | 405 | /* serializes events for the identical and parent and child devices */ |
aa8734ff | 406 | static void event_queue_manager(struct udev *udev) |
7fafc032 | 407 | { |
7e027927 KS |
408 | struct udev_list_node *loop; |
409 | struct udev_list_node *tmp; | |
085cce37 | 410 | |
d1cc6562 | 411 | start_over: |
0bc74ea7 KS |
412 | if (udev_list_is_empty(&event_list)) { |
413 | if (childs > 0) { | |
414 | err(udev, "event list empty, but childs count is %i", childs); | |
415 | childs = 0; | |
416 | } | |
8ab44e3f | 417 | return; |
0bc74ea7 | 418 | } |
8ab44e3f | 419 | |
0bc74ea7 | 420 | udev_list_node_foreach_safe(loop, tmp, &event_list) { |
7e027927 KS |
421 | struct udev_event *loop_event = node_to_event(loop); |
422 | ||
0bc74ea7 KS |
423 | if (childs >= max_childs) { |
424 | info(udev, "maximum number (%i) of childs reached\n", childs); | |
425 | break; | |
426 | } | |
427 | ||
428 | if (loop_event->pid != 0) | |
429 | continue; | |
430 | ||
431 | /* do not start event if parent or child event is still running */ | |
432 | if (devpath_busy(loop_event) != 0) { | |
aa8734ff KS |
433 | dbg(udev, "delay seq %llu (%s)\n", |
434 | udev_device_get_seqnum(loop_event->dev), | |
435 | udev_device_get_devpath(loop_event->dev)); | |
fc465079 KS |
436 | continue; |
437 | } | |
438 | ||
aa8734ff KS |
439 | event_fork(loop_event); |
440 | dbg(udev, "moved seq %llu to running list\n", udev_device_get_seqnum(loop_event->dev)); | |
d1cc6562 OK |
441 | |
442 | /* retry if events finished in the meantime */ | |
443 | if (sigchilds_waiting) { | |
444 | sigchilds_waiting = 0; | |
445 | reap_sigchilds(); | |
446 | goto start_over; | |
447 | } | |
e825b59b | 448 | } |
88f4b648 KS |
449 | } |
450 | ||
3b47c739 | 451 | /* receive the udevd message from userspace */ |
d59f11e1 | 452 | static void handle_ctrl_msg(struct udev_ctrl *uctrl) |
7fafc032 | 453 | { |
d59f11e1 KS |
454 | struct udev *udev = udev_ctrl_get_udev(uctrl); |
455 | struct udev_ctrl_msg *ctrl_msg; | |
456 | const char *str; | |
457 | int i; | |
7b1cbec9 | 458 | |
d59f11e1 KS |
459 | ctrl_msg = udev_ctrl_receive_msg(uctrl); |
460 | if (ctrl_msg == NULL) | |
b437ec95 | 461 | return; |
4a231017 | 462 | |
d59f11e1 KS |
463 | i = udev_ctrl_get_set_log_level(ctrl_msg); |
464 | if (i >= 0) { | |
465 | info(udev, "udevd message (SET_LOG_PRIORITY) received, log_priority=%i\n", i); | |
466 | udev_set_log_priority(udev, i); | |
0028653c KS |
467 | } |
468 | ||
d59f11e1 | 469 | if (udev_ctrl_get_stop_exec_queue(ctrl_msg) > 0) { |
7d563a17 | 470 | info(udev, "udevd message (STOP_EXEC_QUEUE) received\n"); |
3b47c739 | 471 | stop_exec_q = 1; |
d59f11e1 KS |
472 | } |
473 | ||
474 | if (udev_ctrl_get_start_exec_queue(ctrl_msg) > 0) { | |
7d563a17 | 475 | info(udev, "udevd message (START_EXEC_QUEUE) received\n"); |
3b47c739 | 476 | stop_exec_q = 0; |
aa8734ff | 477 | event_queue_manager(udev); |
d59f11e1 KS |
478 | } |
479 | ||
480 | if (udev_ctrl_get_reload_rules(ctrl_msg) > 0) { | |
7d563a17 | 481 | info(udev, "udevd message (RELOAD_RULES) received\n"); |
c895fd00 | 482 | reload_config = 1; |
3b47c739 | 483 | } |
d59f11e1 KS |
484 | |
485 | str = udev_ctrl_get_set_env(ctrl_msg); | |
486 | if (str != NULL) { | |
aa8734ff KS |
487 | char *key; |
488 | ||
489 | key = strdup(str); | |
490 | if (key != NULL) { | |
491 | char *val; | |
492 | ||
493 | val = strchr(key, '='); | |
494 | if (val != NULL) { | |
495 | val[0] = '\0'; | |
496 | val = &val[1]; | |
497 | if (val[0] == '\0') { | |
498 | info(udev, "udevd message (ENV) received, unset '%s'\n", key); | |
499 | udev_add_property(udev, key, NULL); | |
500 | } else { | |
501 | info(udev, "udevd message (ENV) received, set '%s=%s'\n", key, val); | |
502 | udev_add_property(udev, key, val); | |
503 | } | |
d59f11e1 | 504 | } else { |
aa8734ff | 505 | err(udev, "wrong key format '%s'\n", key); |
d59f11e1 | 506 | } |
aa8734ff | 507 | free(key); |
d59f11e1 | 508 | } |
d59f11e1 KS |
509 | } |
510 | ||
511 | i = udev_ctrl_get_set_max_childs(ctrl_msg); | |
512 | if (i >= 0) { | |
513 | info(udev, "udevd message (SET_MAX_CHILDS) received, max_childs=%i\n", i); | |
514 | max_childs = i; | |
515 | } | |
d59f11e1 | 516 | udev_ctrl_msg_unref(ctrl_msg); |
88f4b648 | 517 | } |
4a231017 | 518 | |
bd284db1 SJR |
519 | /* read inotify messages */ |
520 | static int handle_inotify(struct udev *udev) | |
521 | { | |
522 | int nbytes, pos; | |
523 | char *buf; | |
524 | struct inotify_event *ev; | |
bd284db1 SJR |
525 | |
526 | if ((ioctl(inotify_fd, FIONREAD, &nbytes) < 0) || (nbytes <= 0)) | |
527 | return 0; | |
528 | ||
529 | buf = malloc(nbytes); | |
530 | if (buf == NULL) { | |
531 | err(udev, "error getting buffer for inotify, disable watching\n"); | |
532 | close(inotify_fd); | |
533 | inotify_fd = -1; | |
534 | return 0; | |
535 | } | |
536 | ||
537 | read(inotify_fd, buf, nbytes); | |
538 | ||
80be8c48 | 539 | for (pos = 0; pos < nbytes; pos += sizeof(struct inotify_event) + ev->len) { |
047f88bc | 540 | struct udev_device *dev; |
bd284db1 | 541 | |
80be8c48 | 542 | ev = (struct inotify_event *)(buf + pos); |
b8e96d67 SJR |
543 | if (ev->len) { |
544 | dbg(udev, "inotify event: %x for %s\n", ev->mask, ev->name); | |
545 | reload_config = 1; | |
546 | continue; | |
547 | } | |
548 | ||
047f88bc SJR |
549 | dev = udev_watch_lookup(udev, ev->wd); |
550 | if (dev != NULL) { | |
551 | dbg(udev, "inotify event: %x for %s\n", ev->mask, udev_device_get_devnode(dev)); | |
bd284db1 SJR |
552 | if (ev->mask & IN_CLOSE_WRITE) { |
553 | char filename[UTIL_PATH_SIZE]; | |
554 | int fd; | |
555 | ||
047f88bc SJR |
556 | info(udev, "device %s closed, synthesising 'change'\n", udev_device_get_devnode(dev)); |
557 | util_strlcpy(filename, udev_device_get_syspath(dev), sizeof(filename)); | |
bd284db1 SJR |
558 | util_strlcat(filename, "/uevent", sizeof(filename)); |
559 | fd = open(filename, O_WRONLY); | |
560 | if (fd < 0 || write(fd, "change", 6) < 0) | |
561 | info(udev, "error writing uevent: %m\n"); | |
562 | close(fd); | |
563 | } | |
564 | if (ev->mask & IN_IGNORED) | |
047f88bc SJR |
565 | udev_watch_end(udev, dev); |
566 | ||
567 | udev_device_unref(dev); | |
bd284db1 | 568 | } |
b8e96d67 | 569 | |
bd284db1 SJR |
570 | } |
571 | ||
572 | free (buf); | |
4aca304e | 573 | return 0; |
bd284db1 SJR |
574 | } |
575 | ||
e5a5b54a | 576 | static void asmlinkage sig_handler(int signum) |
7fafc032 | 577 | { |
53921bfa KS |
578 | switch (signum) { |
579 | case SIGINT: | |
580 | case SIGTERM: | |
63cc8f04 | 581 | udev_exit = 1; |
53921bfa | 582 | break; |
2f6cbd19 | 583 | case SIGCHLD: |
f27125f9 | 584 | /* set flag, then write to pipe if needed */ |
5cab7caa | 585 | sigchilds_waiting = 1; |
2f6cbd19 | 586 | break; |
c895fd00 KS |
587 | case SIGHUP: |
588 | reload_config = 1; | |
589 | break; | |
f27125f9 | 590 | } |
5a73b25f | 591 | |
3210a72b | 592 | signal_received = 1; |
33db4b8d | 593 | } |
7fafc032 | 594 | |
f4fc0136 | 595 | static void udev_done(int pid, int exitstatus) |
2f6cbd19 | 596 | { |
7e027927 KS |
597 | struct udev_list_node *loop; |
598 | ||
aa8734ff | 599 | /* find event associated with pid and delete it */ |
0bc74ea7 | 600 | udev_list_node_foreach(loop, &event_list) { |
7e027927 | 601 | struct udev_event *loop_event = node_to_event(loop); |
2f6cbd19 | 602 | |
7e027927 KS |
603 | if (loop_event->pid == pid) { |
604 | info(loop_event->udev, "seq %llu cleanup, pid [%d], status %i, %ld seconds old\n", | |
605 | udev_device_get_seqnum(loop_event->dev), loop_event->pid, | |
606 | exitstatus, time(NULL) - loop_event->queue_time); | |
607 | loop_event->exitstatus = exitstatus; | |
0bc74ea7 | 608 | if (debug_trace) |
27691aa3 | 609 | fprintf(stderr, "exit %s (%llu)\n", |
0bc74ea7 KS |
610 | udev_device_get_syspath(loop_event->dev), |
611 | udev_device_get_seqnum(loop_event->dev)); | |
7e027927 | 612 | event_queue_delete(loop_event); |
0bc74ea7 | 613 | childs--; |
3169e8d1 | 614 | |
0bc74ea7 | 615 | /* there may be dependent events waiting */ |
f27125f9 | 616 | run_exec_q = 1; |
2f6cbd19 KS |
617 | return; |
618 | } | |
619 | } | |
620 | } | |
621 | ||
5cab7caa | 622 | static void reap_sigchilds(void) |
f27125f9 | 623 | { |
40caaeec | 624 | pid_t pid; |
f4fc0136 | 625 | int status; |
ce043f85 | 626 | |
40caaeec | 627 | while (1) { |
f4fc0136 | 628 | pid = waitpid(-1, &status, WNOHANG); |
40caaeec | 629 | if (pid <= 0) |
f27125f9 | 630 | break; |
f4fc0136 KS |
631 | if (WIFEXITED(status)) |
632 | status = WEXITSTATUS(status); | |
82de5983 KS |
633 | else if (WIFSIGNALED(status)) |
634 | status = WTERMSIG(status) + 128; | |
f4fc0136 KS |
635 | else |
636 | status = 0; | |
637 | udev_done(pid, status); | |
f27125f9 | 638 | } |
639 | } | |
640 | ||
78230c0d KS |
641 | static void cleanup_queue_dir(struct udev *udev) |
642 | { | |
643 | char dirname[UTIL_PATH_SIZE]; | |
644 | char filename[UTIL_PATH_SIZE]; | |
645 | DIR *dir; | |
646 | ||
647 | util_strlcpy(filename, udev_get_dev_path(udev), sizeof(filename)); | |
648 | util_strlcat(filename, "/.udev/uevent_seqnum", sizeof(filename)); | |
649 | unlink(filename); | |
650 | ||
651 | util_strlcpy(dirname, udev_get_dev_path(udev), sizeof(dirname)); | |
652 | util_strlcat(dirname, "/.udev/queue", sizeof(dirname)); | |
653 | dir = opendir(dirname); | |
654 | if (dir != NULL) { | |
655 | while (1) { | |
656 | struct dirent *dent; | |
657 | ||
658 | dent = readdir(dir); | |
659 | if (dent == NULL || dent->d_name[0] == '\0') | |
660 | break; | |
661 | if (dent->d_name[0] == '.') | |
662 | continue; | |
663 | util_strlcpy(filename, dirname, sizeof(filename)); | |
664 | util_strlcat(filename, "/", sizeof(filename)); | |
665 | util_strlcat(filename, dent->d_name, sizeof(filename)); | |
666 | unlink(filename); | |
667 | } | |
668 | closedir(dir); | |
669 | rmdir(dirname); | |
670 | } | |
671 | } | |
672 | ||
7d563a17 | 673 | static void export_initial_seqnum(struct udev *udev) |
90cd961e | 674 | { |
17fcfb59 | 675 | char filename[UTIL_PATH_SIZE]; |
90cd961e KS |
676 | int fd; |
677 | char seqnum[32]; | |
678 | ssize_t len = 0; | |
679 | ||
31c1f537 KS |
680 | util_strlcpy(filename, udev_get_sys_path(udev), sizeof(filename)); |
681 | util_strlcat(filename, "/kernel/uevent_seqnum", sizeof(filename)); | |
90cd961e KS |
682 | fd = open(filename, O_RDONLY); |
683 | if (fd >= 0) { | |
684 | len = read(fd, seqnum, sizeof(seqnum)-1); | |
685 | close(fd); | |
686 | } | |
687 | if (len <= 0) { | |
688 | strcpy(seqnum, "0\n"); | |
689 | len = 3; | |
690 | } | |
31c1f537 KS |
691 | util_strlcpy(filename, udev_get_dev_path(udev), sizeof(filename)); |
692 | util_strlcat(filename, "/.udev/uevent_seqnum", sizeof(filename)); | |
54808d77 | 693 | util_create_path(udev, filename); |
90cd961e KS |
694 | fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0644); |
695 | if (fd >= 0) { | |
696 | write(fd, seqnum, len); | |
697 | close(fd); | |
698 | } | |
699 | } | |
700 | ||
59345311 | 701 | int main(int argc, char *argv[]) |
c2cf4012 | 702 | { |
7d563a17 | 703 | struct udev *udev; |
3904a758 | 704 | int fd; |
f8911dbb | 705 | struct sigaction act; |
a15f42c4 | 706 | const char *value; |
561d4c5a | 707 | int daemonize = 0; |
5f03ed8a | 708 | int resolve_names = 1; |
b52a01ee | 709 | static const struct option options[] = { |
033e9f8c KS |
710 | { "daemon", no_argument, NULL, 'd' }, |
711 | { "debug-trace", no_argument, NULL, 't' }, | |
712 | { "debug", no_argument, NULL, 'D' }, | |
713 | { "help", no_argument, NULL, 'h' }, | |
714 | { "version", no_argument, NULL, 'V' }, | |
5f03ed8a | 715 | { "resolve-names", required_argument, NULL, 'N' }, |
b52a01ee KS |
716 | {} |
717 | }; | |
e3396a2d | 718 | int rc = 1; |
53921bfa | 719 | |
7d563a17 KS |
720 | udev = udev_new(); |
721 | if (udev == NULL) | |
722 | goto exit; | |
723 | ||
7257cb18 | 724 | logging_init("udevd"); |
7d563a17 | 725 | udev_set_log_fn(udev, log_fn); |
aa8734ff | 726 | info(udev, "version %s\n", VERSION); |
c3b1fa66 | 727 | udev_selinux_init(udev); |
95a6f4c8 | 728 | |
b52a01ee | 729 | while (1) { |
7d563a17 KS |
730 | int option; |
731 | ||
c70560fe | 732 | option = getopt_long(argc, argv, "dDthV", options, NULL); |
b52a01ee KS |
733 | if (option == -1) |
734 | break; | |
735 | ||
736 | switch (option) { | |
737 | case 'd': | |
561d4c5a | 738 | daemonize = 1; |
b52a01ee | 739 | break; |
c7c00276 KS |
740 | case 't': |
741 | debug_trace = 1; | |
742 | break; | |
c70560fe KS |
743 | case 'D': |
744 | debug = 1; | |
7d563a17 KS |
745 | if (udev_get_log_priority(udev) < LOG_INFO) |
746 | udev_set_log_priority(udev, LOG_INFO); | |
9e8fe79b | 747 | break; |
5f03ed8a SJR |
748 | case 'N': |
749 | if (strcmp (optarg, "early") == 0) { | |
750 | resolve_names = 1; | |
9032f119 SJR |
751 | } else if (strcmp (optarg, "late") == 0) { |
752 | resolve_names = 0; | |
5f03ed8a SJR |
753 | } else if (strcmp (optarg, "never") == 0) { |
754 | resolve_names = -1; | |
755 | } else { | |
9032f119 SJR |
756 | fprintf(stderr, "resolve-names must be early, late or never\n"); |
757 | err(udev, "resolve-names must be early, late or never\n"); | |
5f03ed8a SJR |
758 | goto exit; |
759 | } | |
760 | break; | |
b52a01ee | 761 | case 'h': |
6469c772 KS |
762 | printf("Usage: udevd [--help] [--daemon] [--debug-trace] [--debug] " |
763 | "[--resolve-names=early|late|never] [--version]\n"); | |
841e168c MS |
764 | goto exit; |
765 | case 'V': | |
01618658 | 766 | printf("%s\n", VERSION); |
e3396a2d | 767 | goto exit; |
b52a01ee KS |
768 | default: |
769 | goto exit; | |
561d4c5a | 770 | } |
561d4c5a | 771 | } |
40caaeec | 772 | |
fc89fe7e KS |
773 | if (getuid() != 0) { |
774 | fprintf(stderr, "root privileges required\n"); | |
7d563a17 | 775 | err(udev, "root privileges required\n"); |
fc89fe7e KS |
776 | goto exit; |
777 | } | |
778 | ||
5edec024 MS |
779 | /* make sure std{in,out,err} fd's are in a sane state */ |
780 | fd = open("/dev/null", O_RDWR); | |
781 | if (fd < 0) { | |
782 | fprintf(stderr, "cannot open /dev/null\n"); | |
7d563a17 | 783 | err(udev, "cannot open /dev/null\n"); |
5edec024 | 784 | } |
5edec024 MS |
785 | if (write(STDOUT_FILENO, 0, 0) < 0) |
786 | dup2(fd, STDOUT_FILENO); | |
787 | if (write(STDERR_FILENO, 0, 0) < 0) | |
788 | dup2(fd, STDERR_FILENO); | |
789 | ||
d59f11e1 KS |
790 | /* init control socket, bind() ensures, that only one udevd instance is running */ |
791 | udev_ctrl = udev_ctrl_new_from_socket(udev, UDEV_CTRL_SOCK_PATH); | |
792 | if (udev_ctrl == NULL) { | |
793 | fprintf(stderr, "error initializing control socket"); | |
794 | err(udev, "error initializing udevd socket"); | |
795 | rc = 1; | |
796 | goto exit; | |
797 | } | |
798 | ||
799 | if (udev_ctrl_enable_receiving(udev_ctrl) < 0) { | |
800 | fprintf(stderr, "error binding control socket, seems udevd is already running\n"); | |
801 | err(udev, "error binding control socket, seems udevd is already running\n"); | |
802 | rc = 1; | |
833b3c68 KS |
803 | goto exit; |
804 | } | |
805 | ||
aa8734ff KS |
806 | kernel_monitor = udev_monitor_new_from_netlink(udev); |
807 | if (kernel_monitor == NULL || udev_monitor_enable_receiving(kernel_monitor) < 0) { | |
e3396a2d | 808 | fprintf(stderr, "error initializing netlink socket\n"); |
7d563a17 | 809 | err(udev, "error initializing netlink socket\n"); |
833b3c68 KS |
810 | rc = 3; |
811 | goto exit; | |
812 | } | |
cb25a958 | 813 | udev_monitor_set_receive_buffer_size(kernel_monitor, 128*1024*1024); |
833b3c68 | 814 | |
5f03ed8a | 815 | rules = udev_rules_new(udev, resolve_names); |
d7ddce18 KS |
816 | if (rules == NULL) { |
817 | err(udev, "error reading rules\n"); | |
818 | goto exit; | |
819 | } | |
0bc74ea7 | 820 | udev_list_init(&event_list); |
78230c0d | 821 | cleanup_queue_dir(udev); |
7d563a17 | 822 | export_initial_seqnum(udev); |
90cd961e | 823 | |
561d4c5a | 824 | if (daemonize) { |
f15515b5 KS |
825 | pid_t pid; |
826 | ||
827 | pid = fork(); | |
828 | switch (pid) { | |
829 | case 0: | |
7d563a17 | 830 | dbg(udev, "daemonized fork running\n"); |
f15515b5 KS |
831 | break; |
832 | case -1: | |
659353f5 | 833 | err(udev, "fork of daemon failed: %m\n"); |
833b3c68 | 834 | rc = 4; |
f15515b5 KS |
835 | goto exit; |
836 | default: | |
7d563a17 | 837 | dbg(udev, "child [%u] running, parent exits\n", pid); |
2f64aa40 | 838 | rc = 0; |
833b3c68 | 839 | goto exit; |
f15515b5 KS |
840 | } |
841 | } | |
842 | ||
d59f11e1 | 843 | /* redirect std{out,err} */ |
0bc74ea7 KS |
844 | if (!debug && !debug_trace) { |
845 | dup2(fd, STDIN_FILENO); | |
5edec024 | 846 | dup2(fd, STDOUT_FILENO); |
d59f11e1 KS |
847 | dup2(fd, STDERR_FILENO); |
848 | } | |
5edec024 MS |
849 | if (fd > STDERR_FILENO) |
850 | close(fd); | |
e3396a2d | 851 | |
3904a758 | 852 | /* set scheduling priority for the daemon */ |
085cce37 KS |
853 | setpriority(PRIO_PROCESS, 0, UDEVD_PRIORITY); |
854 | ||
3904a758 | 855 | chdir("/"); |
74adec7d | 856 | umask(022); |
3bc7c84c | 857 | setsid(); |
3904a758 KS |
858 | |
859 | /* OOM_DISABLE == -17 */ | |
860 | fd = open("/proc/self/oom_adj", O_RDWR); | |
861 | if (fd < 0) | |
659353f5 | 862 | err(udev, "error disabling OOM: %m\n"); |
3904a758 KS |
863 | else { |
864 | write(fd, "-17", 3); | |
865 | close(fd); | |
866 | } | |
867 | ||
798d7ab6 KS |
868 | fd = open("/dev/kmsg", O_WRONLY); |
869 | if (fd > 0) { | |
f13e4c36 KS |
870 | const char *ver_str = "<6>udev: starting version " VERSION "\n"; |
871 | char path[UTIL_PATH_SIZE]; | |
872 | struct stat statbuf; | |
873 | ||
874 | write(fd, ver_str, strlen(ver_str)); | |
875 | util_strlcpy(path, udev_get_sys_path(udev), sizeof(path)); | |
876 | util_strlcat(path, "/class/mem/null", sizeof(path)); | |
877 | if (lstat(path, &statbuf) == 0) { | |
878 | if (S_ISDIR(statbuf.st_mode)) { | |
64be1437 KS |
879 | const char *depr_str = |
880 | "<6>udev: deprecated sysfs layout; update the kernel or " | |
881 | "disable CONFIG_SYSFS_DEPRECATED; some udev features will " | |
882 | "not work correctly\n"; | |
f13e4c36 KS |
883 | |
884 | write(fd, depr_str, strlen(depr_str)); | |
885 | } | |
886 | } | |
798d7ab6 KS |
887 | close(fd); |
888 | } | |
889 | ||
f27125f9 | 890 | /* set signal handlers */ |
0786e8e5 | 891 | memset(&act, 0x00, sizeof(struct sigaction)); |
6b493a20 | 892 | act.sa_handler = (void (*)(int)) sig_handler; |
f27125f9 | 893 | sigemptyset(&act.sa_mask); |
5db88229 | 894 | act.sa_flags = SA_RESTART; |
f8911dbb KS |
895 | sigaction(SIGINT, &act, NULL); |
896 | sigaction(SIGTERM, &act, NULL); | |
f8911dbb | 897 | sigaction(SIGCHLD, &act, NULL); |
63cc8f04 | 898 | sigaction(SIGHUP, &act, NULL); |
7fafc032 | 899 | |
c895fd00 | 900 | /* watch rules directory */ |
bd284db1 | 901 | udev_watch_init(udev); |
254d6d3c | 902 | if (inotify_fd >= 0) { |
7d563a17 KS |
903 | if (udev_get_rules_path(udev) != NULL) { |
904 | inotify_add_watch(inotify_fd, udev_get_rules_path(udev), | |
282988c4 KS |
905 | IN_CREATE | IN_DELETE | IN_MOVE | IN_CLOSE_WRITE); |
906 | } else { | |
0bc74ea7 | 907 | char filename[UTIL_PATH_SIZE]; |
282988c4 | 908 | |
01618658 | 909 | inotify_add_watch(inotify_fd, UDEV_PREFIX "/lib/udev/rules.d", |
282988c4 | 910 | IN_CREATE | IN_DELETE | IN_MOVE | IN_CLOSE_WRITE); |
01618658 | 911 | inotify_add_watch(inotify_fd, SYSCONFDIR "/udev/rules.d", |
282988c4 KS |
912 | IN_CREATE | IN_DELETE | IN_MOVE | IN_CLOSE_WRITE); |
913 | ||
914 | /* watch dynamic rules directory */ | |
31c1f537 KS |
915 | util_strlcpy(filename, udev_get_dev_path(udev), sizeof(filename)); |
916 | util_strlcat(filename, "/.udev/rules.d", sizeof(filename)); | |
282988c4 KS |
917 | inotify_add_watch(inotify_fd, filename, |
918 | IN_CREATE | IN_DELETE | IN_MOVE | IN_CLOSE_WRITE); | |
919 | } | |
bd284db1 SJR |
920 | |
921 | udev_watch_restore(udev); | |
922 | } | |
0028653c | 923 | |
0bc74ea7 KS |
924 | /* in trace mode run one event after the other */ |
925 | if (debug_trace) { | |
926 | max_childs = 1; | |
927 | } else { | |
f051e340 KS |
928 | int memsize = mem_size_mb(); |
929 | if (memsize > 0) | |
930 | max_childs = 128 + (memsize / 4); | |
931 | else | |
932 | max_childs = UDEVD_MAX_CHILDS; | |
933 | } | |
0bc74ea7 KS |
934 | /* possibly overwrite maximum limit of executed events */ |
935 | value = getenv("UDEVD_MAX_CHILDS"); | |
936 | if (value) | |
937 | max_childs = strtoul(value, NULL, 10); | |
7d563a17 | 938 | info(udev, "initialize max_childs to %u\n", max_childs); |
a15f42c4 | 939 | |
63cc8f04 | 940 | while (!udev_exit) { |
3210a72b | 941 | sigset_t blocked_mask, orig_mask; |
e9a77fd8 | 942 | struct pollfd pfd[4]; |
3210a72b | 943 | struct pollfd *ctrl_poll, *monitor_poll, *inotify_poll = NULL; |
e9a77fd8 KS |
944 | int nfds = 0; |
945 | int fdcount; | |
3210a72b OK |
946 | |
947 | sigfillset(&blocked_mask); | |
948 | sigprocmask(SIG_SETMASK, &blocked_mask, &orig_mask); | |
949 | if (signal_received) { | |
950 | sigprocmask(SIG_SETMASK, &orig_mask, NULL); | |
951 | goto handle_signals; | |
952 | } | |
021a294c | 953 | |
e9a77fd8 KS |
954 | ctrl_poll = &pfd[nfds++]; |
955 | ctrl_poll->fd = udev_ctrl_get_fd(udev_ctrl); | |
956 | ctrl_poll->events = POLLIN; | |
957 | ||
958 | monitor_poll = &pfd[nfds++]; | |
959 | monitor_poll->fd = udev_monitor_get_fd(kernel_monitor); | |
960 | monitor_poll->events = POLLIN; | |
961 | ||
962 | if (inotify_fd >= 0) { | |
963 | inotify_poll = &pfd[nfds++]; | |
964 | inotify_poll->fd = inotify_fd; | |
965 | inotify_poll->events = POLLIN; | |
966 | } | |
3210a72b OK |
967 | |
968 | fdcount = ppoll(pfd, nfds, NULL, &orig_mask); | |
969 | sigprocmask(SIG_SETMASK, &orig_mask, NULL); | |
40caaeec | 970 | if (fdcount < 0) { |
3210a72b OK |
971 | if (errno == EINTR) |
972 | goto handle_signals; | |
973 | err(udev, "error in select: %m\n"); | |
f27125f9 | 974 | continue; |
2f6cbd19 | 975 | } |
e5a2989e | 976 | |
b3518c16 | 977 | /* get control message */ |
3210a72b | 978 | if (ctrl_poll->revents & POLLIN) |
d59f11e1 | 979 | handle_ctrl_msg(udev_ctrl); |
88f4b648 | 980 | |
aa8734ff | 981 | /* get kernel uevent */ |
3210a72b | 982 | if (monitor_poll->revents & POLLIN) { |
aa8734ff KS |
983 | struct udev_device *dev; |
984 | ||
985 | dev = udev_monitor_receive_device(kernel_monitor); | |
986 | if (dev != NULL) { | |
987 | struct udev_event *event; | |
988 | ||
989 | event = udev_event_new(dev); | |
990 | if (event != NULL) | |
991 | event_queue_insert(event); | |
992 | else | |
993 | udev_device_unref(dev); | |
994 | } | |
021a294c | 995 | } |
e5a2989e | 996 | |
c895fd00 | 997 | /* rules directory inotify watch */ |
bd284db1 | 998 | if (inotify_poll && (inotify_poll->revents & POLLIN)) |
4aca304e | 999 | handle_inotify(udev); |
c895fd00 | 1000 | |
3210a72b OK |
1001 | handle_signals: |
1002 | signal_received = 0; | |
1003 | ||
e3396a2d | 1004 | /* rules changed, set by inotify or a HUP signal */ |
c895fd00 | 1005 | if (reload_config) { |
d7ddce18 KS |
1006 | struct udev_rules *rules_new; |
1007 | ||
c895fd00 | 1008 | reload_config = 0; |
5f03ed8a | 1009 | rules_new = udev_rules_new(udev, resolve_names); |
d7ddce18 KS |
1010 | if (rules_new != NULL) { |
1011 | udev_rules_unref(rules); | |
1012 | rules = rules_new; | |
1013 | } | |
c895fd00 KS |
1014 | } |
1015 | ||
5cab7caa KS |
1016 | if (sigchilds_waiting) { |
1017 | sigchilds_waiting = 0; | |
1018 | reap_sigchilds(); | |
f27125f9 | 1019 | } |
e5a2989e | 1020 | |
f27125f9 | 1021 | if (run_exec_q) { |
f27125f9 | 1022 | run_exec_q = 0; |
3b47c739 | 1023 | if (!stop_exec_q) |
aa8734ff | 1024 | event_queue_manager(udev); |
53921bfa | 1025 | } |
53921bfa | 1026 | } |
c969f880 | 1027 | cleanup_queue_dir(udev); |
e3396a2d | 1028 | rc = 0; |
53921bfa | 1029 | exit: |
d7ddce18 | 1030 | udev_rules_unref(rules); |
d59f11e1 | 1031 | udev_ctrl_unref(udev_ctrl); |
90cd961e | 1032 | if (inotify_fd >= 0) |
c895fd00 | 1033 | close(inotify_fd); |
aa8734ff | 1034 | udev_monitor_unref(kernel_monitor); |
c3b1fa66 | 1035 | udev_selinux_exit(udev); |
e598c573 | 1036 | udev_unref(udev); |
7257cb18 | 1037 | logging_close(); |
833b3c68 | 1038 | return rc; |
7fafc032 | 1039 | } |