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.
25 #include <sys/types.h>
41 #define BUFFER_SIZE 1024
42 #define EVENT_TIMEOUT_SECONDS 10
43 #define DAEMON_TIMEOUT_SECONDS 30
46 static int expect_seqnum = 0;
47 static struct hotplug_msg *head = NULL;
50 static void sig_alarmhandler(int signum)
52 dbg("caught signal %d", signum);
55 dbg("event timeout reached");
59 dbg("unhandled signal");
63 static void dump_queue(void)
65 struct hotplug_msg *p;
68 dbg("next expected sequence is %d", expect_seqnum);
70 dbg("sequence %d in queue", p->seqnum);
75 static void dump_msg(struct hotplug_msg *pmsg)
77 dbg("sequence %d, '%s', '%s', '%s'",
78 pmsg->seqnum, pmsg->action, pmsg->devpath, pmsg->subsystem);
81 static int dispatch_msg(struct hotplug_msg *pmsg)
85 extern char **environ;
89 setenv("ACTION", pmsg->action, 1);
90 setenv("DEVPATH", pmsg->devpath, 1);
91 argv[0] = DEFAULT_UDEV_EXEC;
92 argv[1] = pmsg->subsystem;
99 execve(argv[0], argv, environ);
100 dbg("exec of child failed");
104 dbg("fork of child failed");
112 static void set_timer(int seconds)
114 signal(SIGALRM, sig_alarmhandler);
118 static void check_queue(void)
120 struct hotplug_msg *p;
124 while(head != NULL && head->seqnum == expect_seqnum) {
132 set_timer(EVENT_TIMEOUT_SECONDS);
134 set_timer(DAEMON_TIMEOUT_SECONDS);
137 static void add_queue(struct hotplug_msg *pmsg)
139 struct hotplug_msg *pnewmsg;
140 struct hotplug_msg *p;
141 struct hotplug_msg *p1;
145 pnewmsg = malloc(sizeof(struct hotplug_msg));
147 pnewmsg->next = NULL;
148 while(p != NULL && pmsg->seqnum > p->seqnum) {
161 static int lock_file = -1;
162 static char *lock_filename = ".udevd_lock";
164 static int process_queue(void)
168 struct hotplug_msg *pmsg;
169 char buf[BUFFER_SIZE];
172 key = ftok(DEFAULT_UDEVD_EXEC, IPC_KEY_ID);
173 pmsg = (struct hotplug_msg *) buf;
174 msgid = msgget(key, IPC_CREAT);
176 dbg("open message queue error");
180 ret = msgrcv(msgid, (struct msgbuf *) buf, BUFFER_SIZE-4, HOTPLUGMSGTYPE, 0);
182 dbg("current sequence %d, expected sequence %d", pmsg->seqnum, expect_seqnum);
184 /* init expected sequence with value from first call */
185 if (expect_seqnum == 0) {
186 expect_seqnum = pmsg->seqnum;
187 dbg("init next expected sequence number to %d", expect_seqnum);
190 if (pmsg->seqnum > expect_seqnum) {
192 set_timer(EVENT_TIMEOUT_SECONDS);
194 if (pmsg->seqnum == expect_seqnum) {
199 dbg("timeout event for unexpected sequence number %d", pmsg->seqnum);
203 if (errno == EINTR) {
205 /* event timeout, skip all missing, proceed with next queued event */
206 info("timeout reached, skip events %d - %d", expect_seqnum, head->seqnum-1);
207 expect_seqnum = head->seqnum;
209 info("we have nothing to do, so daemon exits...");
210 if (lock_file >= 0) {
212 unlink(lock_filename);
218 dbg("ipc message receive error '%s'", strerror(errno));
225 static void sig_handler(int signum)
227 dbg("caught signal %d", signum);
232 if (lock_file >= 0) {
234 unlink(lock_filename);
240 dbg("unhandled signal");
244 static int one_and_only(void)
248 lock_file = open(lock_filename, O_RDWR | O_CREAT, 0x640);
250 /* see if we can open */
254 /* see if we can lock */
255 if (lockf(lock_file, F_TLOCK, 0) < 0) {
257 unlink(lock_filename);
261 snprintf(string, sizeof(string), "%d\n", getpid());
262 write(lock_file, string, strlen(string));
267 int main(int argc, char *argv[])
269 /* only let one version of the daemon run at any one time */
270 if (one_and_only() != 0)
273 /* set up signal handler */
274 signal(SIGINT, sig_handler);
275 signal(SIGTERM, sig_handler);
276 signal(SIGKILL, sig_handler);
278 /* we exit if we have nothing to do, next event will start us again */
279 set_timer(DAEMON_TIMEOUT_SECONDS);