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);