]> git.ipfire.org Git - thirdparty/systemd.git/blame - udevd.c
[PATCH] allow dbus code to actually build again.
[thirdparty/systemd.git] / udevd.c
CommitLineData
7fafc032
KS
1/*
2 * udevd.c
3 *
4 * Userspace devfs
5 *
6 * Copyright (C) 2004 Ling, Xiaofeng <xiaofeng.ling@intel.com>
7 * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
8 *
9 *
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.
13 *
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.
18 *
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.
22 *
23 */
24
a695feae 25#include <stddef.h>
7fafc032
KS
26#include <sys/types.h>
27#include <sys/ipc.h>
90c210eb 28#include <sys/wait.h>
7fafc032
KS
29#include <sys/msg.h>
30#include <signal.h>
31#include <unistd.h>
32#include <errno.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
a695feae 36#include <time.h>
1c5c245e 37#include <fcntl.h>
7fafc032 38
a695feae 39#include "list.h"
7fafc032
KS
40#include "udev.h"
41#include "udevd.h"
42#include "logging.h"
43
33db4b8d 44#define BUFFER_SIZE 1024
7fafc032
KS
45
46static int expect_seqnum = 0;
a695feae
KS
47static int lock_file = -1;
48static char *lock_filename = ".udevd_lock";
7fafc032 49
a695feae 50LIST_HEAD(msg_list);
7fafc032 51
a695feae 52static void sig_handler(int signum)
7fafc032
KS
53{
54 dbg("caught signal %d", signum);
55 switch (signum) {
56 case SIGALRM:
7fafc032
KS
57 dbg("event timeout reached");
58 break;
a695feae
KS
59 case SIGINT:
60 case SIGTERM:
61 case SIGKILL:
62 if (lock_file >= 0) {
63 close(lock_file);
64 unlink(lock_filename);
65 }
66 exit(20 + signum);
67 break;
7fafc032
KS
68 default:
69 dbg("unhandled signal");
70 }
71}
72
73static void dump_queue(void)
74{
a695feae 75 struct hotplug_msg *msg;
7fafc032 76
a695feae
KS
77 list_for_each_entry(msg, &msg_list, list)
78 dbg("sequence %d in queue", msg->seqnum);
7fafc032
KS
79}
80
a695feae 81static void dump_msg(struct hotplug_msg *msg)
7fafc032
KS
82{
83 dbg("sequence %d, '%s', '%s', '%s'",
a695feae 84 msg->seqnum, msg->action, msg->devpath, msg->subsystem);
7fafc032
KS
85}
86
a695feae 87static int dispatch_msg(struct hotplug_msg *msg)
7fafc032 88{
90c210eb 89 pid_t pid;
90c210eb 90
a695feae 91 dump_msg(msg);
90c210eb 92
a695feae
KS
93 setenv("ACTION", msg->action, 1);
94 setenv("DEVPATH", msg->devpath, 1);
90c210eb
KS
95
96 pid = fork();
97 switch (pid) {
98 case 0:
33db4b8d 99 /* child */
a695feae 100 execl(UDEV_EXEC, "udev", msg->subsystem, NULL);
33db4b8d
KS
101 dbg("exec of child failed");
102 exit(1);
90c210eb
KS
103 break;
104 case -1:
33db4b8d 105 dbg("fork of child failed");
90c210eb
KS
106 return -1;
107 default:
a695feae 108 wait(NULL);
90c210eb
KS
109 }
110 return 0;
7fafc032
KS
111}
112
a695feae 113static void set_timeout(int seconds)
7fafc032 114{
33db4b8d 115 alarm(seconds);
a695feae 116 dbg("set timeout in %d seconds", seconds);
7fafc032
KS
117}
118
119static void check_queue(void)
120{
a695feae
KS
121 struct hotplug_msg *msg;
122 struct hotplug_msg *tmp_msg;
123 time_t msg_age;
124
125recheck:
126 /* dispatch events until one is missing */
127 list_for_each_entry_safe(msg, tmp_msg, &msg_list, list) {
128 if (msg->seqnum != expect_seqnum)
129 break;
130 dispatch_msg(msg);
7fafc032 131 expect_seqnum++;
a695feae
KS
132 list_del_init(&msg->list);
133 free(msg);
134 }
135
136 /* recalculate timeout */
137 if (list_empty(&msg_list) == 0) {
138 msg_age = time(NULL) - msg->queue_time;
139 if (msg_age > EVENT_TIMEOUT_SECONDS-1) {
140 info("event %d, age %li seconds, skip event %d-%d",
141 msg->seqnum, msg_age, expect_seqnum, msg->seqnum-1);
142 expect_seqnum = msg->seqnum;
143 goto recheck;
144 }
145 set_timeout(EVENT_TIMEOUT_SECONDS - msg_age);
146 return;
7fafc032 147 }
a695feae
KS
148
149 /* queue is empty */
150 set_timeout(UDEVD_TIMEOUT_SECONDS);
7fafc032
KS
151}
152
a695feae 153static int queue_msg(struct hotplug_msg *msg)
7fafc032 154{
a695feae
KS
155 struct hotplug_msg *new_msg;
156 struct hotplug_msg *tmp_msg;
157
158 new_msg = malloc(sizeof(*new_msg));
159 if (new_msg == NULL) {
160 dbg("error malloc");
161 return -ENOMEM;
7fafc032 162 }
a695feae 163 memcpy(new_msg, msg, sizeof(*new_msg));
7fafc032 164
a695feae
KS
165 /* store timestamp of queuing */
166 new_msg->queue_time = time(NULL);
167
168 /* sort message by sequence number into list*/
169 list_for_each_entry(tmp_msg, &msg_list, list)
170 if (tmp_msg->seqnum > new_msg->seqnum)
171 break;
172 list_add_tail(&new_msg->list, &tmp_msg->list);
173
174 return 0;
175}
1c5c245e 176
a695feae 177static void work(void)
7fafc032 178{
a695feae 179 struct hotplug_msg *msg;
7fafc032
KS
180 int msgid;
181 key_t key;
7fafc032
KS
182 char buf[BUFFER_SIZE];
183 int ret;
184
a695feae
KS
185 key = ftok(UDEVD_EXEC, IPC_KEY_ID);
186 msg = (struct hotplug_msg *) buf;
7fafc032
KS
187 msgid = msgget(key, IPC_CREAT);
188 if (msgid == -1) {
189 dbg("open message queue error");
a695feae 190 exit(1);
7fafc032
KS
191 }
192 while (1) {
193 ret = msgrcv(msgid, (struct msgbuf *) buf, BUFFER_SIZE-4, HOTPLUGMSGTYPE, 0);
194 if (ret != -1) {
a695feae 195 /* init the expected sequence with value from first call */
7fafc032 196 if (expect_seqnum == 0) {
a695feae 197 expect_seqnum = msg->seqnum;
7fafc032
KS
198 dbg("init next expected sequence number to %d", expect_seqnum);
199 }
a695feae
KS
200 dbg("current sequence %d, expected sequence %d", msg->seqnum, expect_seqnum);
201 if (msg->seqnum == expect_seqnum) {
202 /* execute expected event */
203 dispatch_msg(msg);
204 expect_seqnum++;
205 check_queue();
206 dump_queue();
207 continue;
7fafc032 208 }
a695feae
KS
209 if (msg->seqnum > expect_seqnum) {
210 /* something missing, queue event*/
211 queue_msg(msg);
212 check_queue();
213 dump_queue();
214 continue;
215 }
216 dbg("too late for event with sequence %d, even skipped ", msg->seqnum);
33db4b8d 217 } else {
7fafc032 218 if (errno == EINTR) {
a695feae
KS
219 /* timeout */
220 if (list_empty(&msg_list)) {
33db4b8d 221 info("we have nothing to do, so daemon exits...");
1c5c245e
GKH
222 if (lock_file >= 0) {
223 close(lock_file);
224 unlink(lock_filename);
225 }
33db4b8d 226 exit(0);
7fafc032
KS
227 }
228 check_queue();
a695feae
KS
229 dump_queue();
230 continue;
7fafc032 231 }
a695feae 232 dbg("ipc message receive error '%s'", strerror(errno));
33db4b8d 233 }
7fafc032 234 }
33db4b8d 235}
7fafc032 236
1c5c245e
GKH
237static int one_and_only(void)
238{
239 char string[100];
240
241 lock_file = open(lock_filename, O_RDWR | O_CREAT, 0x640);
242
243 /* see if we can open */
244 if (lock_file < 0)
a695feae 245 return -1;
1c5c245e
GKH
246
247 /* see if we can lock */
248 if (lockf(lock_file, F_TLOCK, 0) < 0) {
249 close(lock_file);
250 unlink(lock_filename);
a695feae 251 return -1;
1c5c245e
GKH
252 }
253
254 snprintf(string, sizeof(string), "%d\n", getpid());
255 write(lock_file, string, strlen(string));
a695feae 256
1c5c245e
GKH
257 return 0;
258}
259
33db4b8d
KS
260int main(int argc, char *argv[])
261{
1c5c245e
GKH
262 /* only let one version of the daemon run at any one time */
263 if (one_and_only() != 0)
264 exit(0);
265
7fafc032
KS
266 /* set up signal handler */
267 signal(SIGINT, sig_handler);
268 signal(SIGTERM, sig_handler);
269 signal(SIGKILL, sig_handler);
a695feae 270 signal(SIGALRM, sig_handler);
33db4b8d
KS
271
272 /* we exit if we have nothing to do, next event will start us again */
a695feae 273 set_timeout(UDEVD_TIMEOUT_SECONDS);
7fafc032 274
a695feae
KS
275 work();
276 exit(0);
7fafc032 277}