]>
git.ipfire.org Git - thirdparty/systemd.git/blob - udevd.c
6 * Copyright (C) 2004 Ling, Xiaofeng <xiaofeng.ling@intel.com>
7 * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation version 2 of the License.
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include <sys/types.h>
41 #include "udev_version.h"
46 #define BUFFER_SIZE 1024
48 static int running_remove_queue(pid_t pid
);
49 static int msg_exec(struct hotplug_msg
*msg
);
51 static int expect_seqnum
= 0;
52 static int lock_file
= -1;
53 static char *lock_filename
= ".udevd_lock";
56 LIST_HEAD(running_list
);
57 LIST_HEAD(delayed_list
);
59 static void sig_handler(int signum
)
63 dbg("caught signal %d", signum
);
66 dbg("event timeout reached");
69 /* catch signals from exiting childs */
70 while ( (pid
= waitpid(-1, NULL
, WNOHANG
)) > 0) {
71 dbg("exec finished, pid %d", pid
);
72 running_remove_queue(pid
);
79 unlink(lock_filename
);
84 dbg("unhandled signal");
88 static void set_timeout(int seconds
)
91 dbg("set timeout in %d seconds", seconds
);
94 static int running_moveto_queue(struct hotplug_msg
*msg
)
96 dbg("move sequence %d [%d] to running queue '%s'",
97 msg
->seqnum
, msg
->pid
, msg
->devpath
);
98 list_move_tail(&msg
->list
, &running_list
);
102 static int running_remove_queue(pid_t pid
)
104 struct hotplug_msg
*child
;
105 struct hotplug_msg
*tmp_child
;
107 list_for_each_entry_safe(child
, tmp_child
, &running_list
, list
)
108 if (child
->pid
== pid
) {
109 list_del_init(&child
->list
);
116 static pid_t
running_getpid_by_devpath(struct hotplug_msg
*msg
)
118 struct hotplug_msg
*child
;
119 struct hotplug_msg
*tmp_child
;
121 list_for_each_entry_safe(child
, tmp_child
, &running_list
, list
)
122 if (strncmp(child
->devpath
, msg
->devpath
, sizeof(child
->devpath
)) == 0)
127 static void delayed_dump_queue(void)
129 struct hotplug_msg
*child
;
131 list_for_each_entry(child
, &delayed_list
, list
)
132 dbg("event for '%s' in queue", child
->devpath
);
135 static int delayed_moveto_queue(struct hotplug_msg
*msg
)
137 dbg("move event to delayed queue '%s'", msg
->devpath
);
138 list_move_tail(&msg
->list
, &delayed_list
);
142 static void delayed_check_queue(void)
144 struct hotplug_msg
*delayed_child
;
145 struct hotplug_msg
*running_child
;
146 struct hotplug_msg
*tmp_child
;
148 /* see if we have delayed exec's that can run now */
149 list_for_each_entry_safe(delayed_child
, tmp_child
, &delayed_list
, list
)
150 list_for_each_entry_safe(running_child
, tmp_child
, &running_list
, list
)
151 if (strncmp(delayed_child
->devpath
, running_child
->devpath
,
152 sizeof(running_child
->devpath
)) == 0) {
153 dbg("delayed exec for '%s' can run now", delayed_child
->devpath
);
154 msg_exec(delayed_child
);
158 static void msg_dump(struct hotplug_msg
*msg
)
160 dbg("sequence %d, '%s', '%s', '%s'",
161 msg
->seqnum
, msg
->action
, msg
->devpath
, msg
->subsystem
);
164 static int msg_exec(struct hotplug_msg
*msg
)
170 setenv("ACTION", msg
->action
, 1);
171 setenv("DEVPATH", msg
->devpath
, 1);
173 /* delay exec, if we already have a udev working on the same devpath */
174 pid
= running_getpid_by_devpath(msg
);
176 dbg("delay exec of sequence %d, [%d] already working on '%s'",
177 msg
->seqnum
, pid
, msg
->devpath
);
178 delayed_moveto_queue(msg
);
185 execl(UDEV_BIN
, "udev", msg
->subsystem
, NULL
);
186 dbg("exec of child failed");
190 dbg("fork of child failed");
193 /* exec in background, get the SIGCHLD with the sig handler */
195 running_moveto_queue(msg
);
201 static void msg_dump_queue(void)
203 struct hotplug_msg
*msg
;
205 list_for_each_entry(msg
, &msg_list
, list
)
206 dbg("sequence %d in queue", msg
->seqnum
);
209 static void msg_check_queue(void)
211 struct hotplug_msg
*msg
;
212 struct hotplug_msg
*tmp_msg
;
216 /* dispatch events until one is missing */
217 list_for_each_entry_safe(msg
, tmp_msg
, &msg_list
, list
) {
218 if (msg
->seqnum
!= expect_seqnum
)
224 /* recalculate next timeout */
225 if (list_empty(&msg_list
) == 0) {
226 msg_age
= time(NULL
) - msg
->queue_time
;
227 if (msg_age
> EVENT_TIMEOUT_SEC
-1) {
228 info("event %d, age %li seconds, skip event %d-%d",
229 msg
->seqnum
, msg_age
, expect_seqnum
, msg
->seqnum
-1);
230 expect_seqnum
= msg
->seqnum
;
234 /* the first sequence gets its own timeout */
235 if (expect_seqnum
== 0) {
236 msg_age
= EVENT_TIMEOUT_SEC
- FIRST_EVENT_TIMEOUT_SEC
;
240 set_timeout(EVENT_TIMEOUT_SEC
- msg_age
);
245 static int msg_add_queue(struct hotplug_msg
*msg
)
247 struct hotplug_msg
*new_msg
;
248 struct hotplug_msg
*tmp_msg
;
250 new_msg
= malloc(sizeof(*new_msg
));
251 if (new_msg
== NULL
) {
255 memcpy(new_msg
, msg
, sizeof(*new_msg
));
257 /* store timestamp of queuing */
258 new_msg
->queue_time
= time(NULL
);
260 /* sort message by sequence number into list*/
261 list_for_each_entry(tmp_msg
, &msg_list
, list
)
262 if (tmp_msg
->seqnum
> new_msg
->seqnum
)
264 list_add_tail(&new_msg
->list
, &tmp_msg
->list
);
269 static void work(void)
271 struct hotplug_msg
*msg
;
274 char buf
[BUFFER_SIZE
];
277 key
= ftok(UDEVD_BIN
, IPC_KEY_ID
);
278 msg
= (struct hotplug_msg
*) buf
;
279 msgid
= msgget(key
, IPC_CREAT
);
281 dbg("open message queue error");
285 ret
= msgrcv(msgid
, (struct msgbuf
*) buf
, BUFFER_SIZE
-4, HOTPLUGMSGTYPE
, 0);
287 dbg("received sequence %d, expected sequence %d", msg
->seqnum
, expect_seqnum
);
288 if (msg
->seqnum
>= expect_seqnum
) {
294 dbg("too late for event with sequence %d, event skipped ", msg
->seqnum
);
296 if (errno
== EINTR
) {
299 delayed_check_queue();
300 delayed_dump_queue();
303 dbg("ipc message receive error '%s'", strerror(errno
));
308 static int one_and_only(void)
312 lock_file
= open(lock_filename
, O_RDWR
| O_CREAT
, 0x640);
314 /* see if we can open */
318 /* see if we can lock */
319 if (lockf(lock_file
, F_TLOCK
, 0) < 0) {
324 snprintf(string
, sizeof(string
), "%d\n", getpid());
325 write(lock_file
, string
, strlen(string
));
330 int main(int argc
, char *argv
[])
332 /* only let one version of the daemon run at any one time */
333 if (one_and_only() != 0)
336 /* set up signal handler */
337 signal(SIGINT
, sig_handler
);
338 signal(SIGTERM
, sig_handler
);
339 signal(SIGALRM
, sig_handler
);
340 signal(SIGCHLD
, sig_handler
);