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