]> git.ipfire.org Git - thirdparty/systemd.git/blame - udevd.c
[PATCH] fix log option code so that it actually works for all udev programs.
[thirdparty/systemd.git] / udevd.c
CommitLineData
7fafc032 1/*
53921bfa 2 * udevd.c - hotplug event serializer
7fafc032 3 *
7fafc032 4 * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
2f6cbd19 5 * Copyright (C) 2004 Chris Friesen <chris_friesen@sympatico.ca>
7fafc032
KS
6 *
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation version 2 of the License.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 */
22
a695feae 23#include <stddef.h>
90c210eb 24#include <sys/wait.h>
7fafc032
KS
25#include <signal.h>
26#include <unistd.h>
27#include <errno.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
a695feae 31#include <time.h>
53921bfa
KS
32#include <sys/types.h>
33#include <sys/socket.h>
34#include <sys/un.h>
2f6cbd19 35#include <sys/time.h>
7fafc032 36
a695feae 37#include "list.h"
7fafc032 38#include "udev.h"
35b7d88c 39#include "udev_version.h"
7fafc032
KS
40#include "udevd.h"
41#include "logging.h"
42
53921bfa 43static int expected_seqnum = 0;
2f6cbd19
KS
44volatile static int children_waiting;
45volatile static int msg_q_timeout;
7fafc032 46
a695feae 47LIST_HEAD(msg_list);
53921bfa 48LIST_HEAD(exec_list);
35b7d88c 49LIST_HEAD(running_list);
7fafc032 50
2f6cbd19
KS
51static void exec_queue_manager(void);
52static void msg_queue_manager(void);
7fafc032 53
51a8bb2f
GKH
54unsigned char logname[42];
55
56int log_ok(void)
57{
58 return 1;
59}
60
53921bfa 61static void msg_dump_queue(void)
7fafc032 62{
53921bfa 63 struct hotplug_msg *msg;
7fafc032 64
53921bfa
KS
65 list_for_each_entry(msg, &msg_list, list)
66 dbg("sequence %d in queue", msg->seqnum);
35b7d88c
KS
67}
68
53921bfa 69static void msg_dump(struct hotplug_msg *msg)
35b7d88c 70{
53921bfa
KS
71 dbg("sequence %d, '%s', '%s', '%s'",
72 msg->seqnum, msg->action, msg->devpath, msg->subsystem);
35b7d88c
KS
73}
74
53921bfa 75static struct hotplug_msg *msg_create(void)
35b7d88c 76{
53921bfa 77 struct hotplug_msg *new_msg;
35b7d88c 78
53921bfa 79 new_msg = malloc(sizeof(struct hotplug_msg));
2f6cbd19 80 if (new_msg == NULL)
53921bfa 81 dbg("error malloc");
53921bfa 82 return new_msg;
35b7d88c
KS
83}
84
2f6cbd19 85static void run_queue_delete(struct hotplug_msg *msg)
8e2229c4 86{
2f6cbd19
KS
87 list_del(&msg->list);
88 free(msg);
89 exec_queue_manager();
8e2229c4
KS
90}
91
53921bfa
KS
92/* orders the message in the queue by sequence number */
93static void msg_queue_insert(struct hotplug_msg *msg)
35b7d88c 94{
53921bfa 95 struct hotplug_msg *loop_msg;
35b7d88c 96
53921bfa
KS
97 /* sort message by sequence number into list*/
98 list_for_each_entry(loop_msg, &msg_list, list)
99 if (loop_msg->seqnum > msg->seqnum)
100 break;
101 list_add_tail(&msg->list, &loop_msg->list);
102 dbg("queued message seq %d", msg->seqnum);
35b7d88c 103
53921bfa
KS
104 /* store timestamp of queuing */
105 msg->queue_time = time(NULL);
35b7d88c 106
2f6cbd19
KS
107 /* run msg queue manager */
108 msg_queue_manager();
7fafc032 109
53921bfa 110 return ;
7fafc032
KS
111}
112
53921bfa 113/* forks event and removes event from run queue when finished */
2f6cbd19 114static void udev_run(struct hotplug_msg *msg)
7fafc032 115{
90c210eb 116 pid_t pid;
a695feae
KS
117 setenv("ACTION", msg->action, 1);
118 setenv("DEVPATH", msg->devpath, 1);
90c210eb
KS
119
120 pid = fork();
121 switch (pid) {
122 case 0:
33db4b8d 123 /* child */
35b7d88c 124 execl(UDEV_BIN, "udev", msg->subsystem, NULL);
33db4b8d
KS
125 dbg("exec of child failed");
126 exit(1);
90c210eb
KS
127 break;
128 case -1:
33db4b8d 129 dbg("fork of child failed");
2f6cbd19
KS
130 run_queue_delete(msg);
131 break;
90c210eb 132 default:
2f6cbd19
KS
133 /* get SIGCHLD in main loop */
134 dbg("==> exec seq %d [%d] working at '%s'", msg->seqnum, pid, msg->devpath);
135 msg->pid = pid;
90c210eb 136 }
7fafc032
KS
137}
138
53921bfa
KS
139/* returns already running task with devpath */
140static struct hotplug_msg *running_with_devpath(struct hotplug_msg *msg)
7fafc032 141{
53921bfa 142 struct hotplug_msg *loop_msg;
2f6cbd19 143 list_for_each_entry(loop_msg, &running_list, list)
53921bfa
KS
144 if (strncmp(loop_msg->devpath, msg->devpath, sizeof(loop_msg->devpath)) == 0)
145 return loop_msg;
146 return NULL;
7fafc032
KS
147}
148
2f6cbd19
KS
149/* exec queue management routine executes the events and delays events for the same devpath */
150static void exec_queue_manager()
7fafc032 151{
53921bfa
KS
152 struct hotplug_msg *loop_msg;
153 struct hotplug_msg *tmp_msg;
a695feae 154 struct hotplug_msg *msg;
53921bfa 155
2f6cbd19
KS
156 list_for_each_entry_safe(loop_msg, tmp_msg, &exec_list, list) {
157 msg = running_with_devpath(loop_msg);
158 if (!msg) {
159 /* move event to run list */
160 list_move_tail(&loop_msg->list, &running_list);
161 udev_run(loop_msg);
162 dbg("moved seq %d to running list", loop_msg->seqnum);
163 } else {
164 dbg("delay seq %d, cause seq %d already working on '%s'",
165 loop_msg->seqnum, msg->seqnum, msg->devpath);
53921bfa 166 }
53921bfa
KS
167 }
168}
169
2f6cbd19 170static void msg_move_exec(struct hotplug_msg *msg)
86590cd5 171{
2f6cbd19
KS
172 list_move_tail(&msg->list, &exec_list);
173 exec_queue_manager();
174 expected_seqnum = msg->seqnum+1;
175 dbg("moved seq %d to exec, next expected is %d",
176 msg->seqnum, expected_seqnum);
86590cd5
KS
177}
178
2f6cbd19
KS
179/* msg queue management routine handles the timeouts and dispatches the events */
180static void msg_queue_manager()
53921bfa
KS
181{
182 struct hotplug_msg *loop_msg;
a695feae 183 struct hotplug_msg *tmp_msg;
53921bfa 184 time_t msg_age = 0;
a695feae 185
2f6cbd19 186 dbg("msg queue manager, next expected is %d", expected_seqnum);
a695feae 187recheck:
2f6cbd19
KS
188 list_for_each_entry_safe(loop_msg, tmp_msg, &msg_list, list) {
189 /* move event with expected sequence to the exec list */
190 if (loop_msg->seqnum == expected_seqnum) {
191 msg_move_exec(loop_msg);
192 continue;
a695feae 193 }
35b7d88c 194
2f6cbd19
KS
195 /* move event with expired timeout to the exec list */
196 msg_age = time(NULL) - loop_msg->queue_time;
197 if (msg_age > EVENT_TIMEOUT_SEC-1) {
198 msg_move_exec(loop_msg);
199 goto recheck;
53921bfa 200 } else {
2f6cbd19 201 break;
53921bfa 202 }
2f6cbd19
KS
203 }
204
205 msg_dump_queue();
206
207 if (list_empty(&msg_list) == 0) {
208 /* set timeout for remaining queued events */
209 struct itimerval itv = {{0, 0}, {EVENT_TIMEOUT_SEC - msg_age, 0}};
210 dbg("next event expires in %li seconds",
211 EVENT_TIMEOUT_SEC - msg_age);
212 setitimer(ITIMER_REAL, &itv, 0);
7fafc032 213 }
7fafc032
KS
214}
215
2f6cbd19
KS
216/* receive the msg, do some basic sanity checks, and queue it */
217static void handle_msg(int sock)
7fafc032 218{
53921bfa
KS
219 struct hotplug_msg *msg;
220 int retval;
a695feae 221
53921bfa
KS
222 msg = msg_create();
223 if (msg == NULL) {
224 dbg("unable to store message");
2f6cbd19 225 return;
7fafc032 226 }
7fafc032 227
53921bfa
KS
228 retval = recv(sock, msg, sizeof(struct hotplug_msg), 0);
229 if (retval < 0) {
2f6cbd19
KS
230 if (errno != EINTR)
231 dbg("unable to receive message");
232 return;
53921bfa 233 }
2f6cbd19 234
53921bfa
KS
235 if (strncmp(msg->magic, UDEV_MAGIC, sizeof(UDEV_MAGIC)) != 0 ) {
236 dbg("message magic '%s' doesn't match, ignore it", msg->magic);
2f6cbd19
KS
237 free(msg);
238 return;
53921bfa 239 }
a695feae 240
86590cd5 241 /* if no seqnum is given, we move straight to exec queue */
2f6cbd19 242 if (msg->seqnum == -1) {
86590cd5 243 list_add(&msg->list, &exec_list);
2f6cbd19 244 exec_queue_manager();
86590cd5 245 } else {
86590cd5 246 msg_queue_insert(msg);
86590cd5 247 }
a695feae 248}
1c5c245e 249
53921bfa 250static void sig_handler(int signum)
7fafc032 251{
53921bfa
KS
252 switch (signum) {
253 case SIGINT:
254 case SIGTERM:
53921bfa
KS
255 exit(20 + signum);
256 break;
2f6cbd19
KS
257 case SIGALRM:
258 msg_q_timeout = 1;
259 break;
260 case SIGCHLD:
261 children_waiting = 1;
262 break;
53921bfa
KS
263 default:
264 dbg("unhandled signal");
7fafc032 265 }
33db4b8d 266}
7fafc032 267
2f6cbd19
KS
268static void udev_done(int pid)
269{
270 /* find msg associated with pid and delete it */
271 struct hotplug_msg *msg;
272
273 list_for_each_entry(msg, &running_list, list) {
274 if (msg->pid == pid) {
275 dbg("<== exec seq %d came back", msg->seqnum);
276 run_queue_delete(msg);
277 return;
278 }
279 }
280}
281
33db4b8d
KS
282int main(int argc, char *argv[])
283{
53921bfa 284 int ssock;
53921bfa 285 struct sockaddr_un saddr;
1dadabd7 286 socklen_t addrlen;
53921bfa
KS
287 int retval;
288
95a6f4c8
GKH
289 init_logging("udevd");
290
7fafc032
KS
291 signal(SIGINT, sig_handler);
292 signal(SIGTERM, sig_handler);
2f6cbd19
KS
293 signal(SIGALRM, sig_handler);
294 signal(SIGCHLD, sig_handler);
295
296 /* we want these two to interrupt system calls */
297 siginterrupt(SIGALRM, 1);
298 siginterrupt(SIGCHLD, 1);
7fafc032 299
53921bfa
KS
300 memset(&saddr, 0x00, sizeof(saddr));
301 saddr.sun_family = AF_LOCAL;
872344c4
KS
302 /* use abstract namespace for socket path */
303 strcpy(&saddr.sun_path[1], UDEVD_SOCK_PATH);
1dadabd7 304 addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(saddr.sun_path+1) + 1;
53921bfa 305
2f6cbd19 306 ssock = socket(AF_LOCAL, SOCK_DGRAM, 0);
53921bfa
KS
307 if (ssock == -1) {
308 dbg("error getting socket");
309 exit(1);
310 }
311
2f6cbd19 312 /* the bind takes care of ensuring only one copy running */
1dadabd7 313 retval = bind(ssock, &saddr, addrlen);
53921bfa
KS
314 if (retval < 0) {
315 dbg("bind failed\n");
316 goto exit;
317 }
318
2f6cbd19
KS
319 while (1) {
320 handle_msg(ssock);
53921bfa 321
2f6cbd19
KS
322 while(msg_q_timeout) {
323 msg_q_timeout = 0;
324 msg_queue_manager();
325 }
53921bfa 326
2f6cbd19
KS
327 while(children_waiting) {
328 children_waiting = 0;
329 /* reap all dead children */
330 while(1) {
331 int pid = waitpid(-1, 0, WNOHANG);
332 if ((pid == -1) || (pid == 0))
333 break;
334 udev_done(pid);
335 }
53921bfa 336 }
53921bfa
KS
337 }
338exit:
339 close(ssock);
53921bfa 340 exit(1);
7fafc032 341}