]>
Commit | Line | Data |
---|---|---|
7fafc032 KS |
1 | /* |
2 | * udevsend.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 | ||
25 | #include <sys/types.h> | |
0be0c18d GKH |
26 | #include <sys/socket.h> |
27 | #include <sys/wait.h> | |
28 | #include <sys/un.h> | |
e5a2989e | 29 | #include <time.h> |
7fafc032 KS |
30 | #include <errno.h> |
31 | #include <stdio.h> | |
32 | #include <stdlib.h> | |
1dadabd7 | 33 | #include <stddef.h> |
7fafc032 | 34 | #include <string.h> |
33db4b8d | 35 | #include <unistd.h> |
2f6cbd19 | 36 | #include <linux/stddef.h> |
7fafc032 KS |
37 | |
38 | #include "udev.h" | |
35b7d88c | 39 | #include "udev_version.h" |
7fafc032 KS |
40 | #include "udevd.h" |
41 | #include "logging.h" | |
42 | ||
13f24d59 KS |
43 | /* global variables */ |
44 | static int sock = -1; | |
45 | ||
6c18b1fb | 46 | #ifdef USE_LOG |
6b493a20 | 47 | void log_message (int priority, const char *format, ...) |
51a8bb2f | 48 | { |
6b493a20 KS |
49 | va_list args; |
50 | ||
51 | if (priority > udev_log_priority) | |
52 | return; | |
d026a35d GKH |
53 | |
54 | va_start(args, format); | |
6b493a20 | 55 | vsyslog(priority, format, args); |
d026a35d | 56 | va_end(args); |
51a8bb2f | 57 | } |
d026a35d | 58 | #endif |
51a8bb2f | 59 | |
33db4b8d KS |
60 | static int start_daemon(void) |
61 | { | |
62 | pid_t pid; | |
63 | pid_t child_pid; | |
4497fcbf KS |
64 | char *const argv[] = { "udevd", NULL }; |
65 | char *const envp[] = { NULL }; | |
33db4b8d KS |
66 | |
67 | pid = fork(); | |
68 | switch (pid) { | |
69 | case 0: | |
70 | /* helper child */ | |
71 | child_pid = fork(); | |
72 | switch (child_pid) { | |
73 | case 0: | |
4497fcbf | 74 | /* daemon with empty environment */ |
13f24d59 | 75 | close(sock); |
4497fcbf | 76 | execve(UDEVD_BIN, argv, envp); |
6b493a20 | 77 | err("exec of daemon failed"); |
4a231017 | 78 | _exit(1); |
33db4b8d | 79 | case -1: |
6b493a20 | 80 | err("fork of daemon failed"); |
33db4b8d KS |
81 | return -1; |
82 | default: | |
83 | exit(0); | |
84 | } | |
85 | break; | |
86 | case -1: | |
6b493a20 | 87 | err("fork of helper failed"); |
33db4b8d KS |
88 | return -1; |
89 | default: | |
e920fed3 | 90 | waitpid(pid, NULL, 0); |
33db4b8d KS |
91 | } |
92 | return 0; | |
93 | } | |
94 | ||
28e169f0 KS |
95 | static void run_udev(const char *subsystem) |
96 | { | |
4497fcbf | 97 | char *const argv[] = { "udev", (char *)subsystem, NULL }; |
28e169f0 KS |
98 | pid_t pid; |
99 | ||
100 | pid = fork(); | |
101 | switch (pid) { | |
102 | case 0: | |
103 | /* child */ | |
4497fcbf | 104 | execv(UDEV_BIN, argv); |
6b493a20 | 105 | err("exec of udev child failed"); |
5cab7caa | 106 | _exit(1); |
28e169f0 KS |
107 | break; |
108 | case -1: | |
6b493a20 | 109 | err("fork of udev child failed"); |
28e169f0 KS |
110 | break; |
111 | default: | |
e920fed3 | 112 | waitpid(pid, NULL, 0); |
28e169f0 KS |
113 | } |
114 | } | |
115 | ||
4a231017 | 116 | int main(int argc, char *argv[], char *envp[]) |
7fafc032 | 117 | { |
4a231017 KS |
118 | static struct udevsend_msg usend_msg; |
119 | int usend_msg_len; | |
120 | int i; | |
33db4b8d | 121 | int loop; |
53921bfa | 122 | struct sockaddr_un saddr; |
1dadabd7 | 123 | socklen_t addrlen; |
4a231017 KS |
124 | int bufpos = 0; |
125 | int retval = 1; | |
2f6cbd19 | 126 | int started_daemon = 0; |
4497fcbf | 127 | const char *subsystem = NULL; |
7fafc032 | 128 | |
7257cb18 | 129 | logging_init("udevsend"); |
6b493a20 KS |
130 | #ifdef USE_LOG |
131 | udev_init_config(); | |
132 | #endif | |
8bbf2751 | 133 | dbg("version %s", UDEV_VERSION); |
95a6f4c8 | 134 | |
2f6cbd19 | 135 | sock = socket(AF_LOCAL, SOCK_DGRAM, 0); |
53921bfa | 136 | if (sock == -1) { |
6b493a20 | 137 | err("error getting socket"); |
28e169f0 | 138 | goto fallback; |
7fafc032 KS |
139 | } |
140 | ||
e5a2989e | 141 | memset(&saddr, 0x00, sizeof(struct sockaddr_un)); |
53921bfa | 142 | saddr.sun_family = AF_LOCAL; |
872344c4 KS |
143 | /* use abstract namespace for socket path */ |
144 | strcpy(&saddr.sun_path[1], UDEVD_SOCK_PATH); | |
1dadabd7 | 145 | addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(saddr.sun_path+1) + 1; |
53921bfa | 146 | |
4a231017 | 147 | memset(&usend_msg, 0x00, sizeof(struct udevsend_msg)); |
4a231017 KS |
148 | strcpy(usend_msg.magic, UDEV_MAGIC); |
149 | ||
150 | /* copy all keys to send buffer */ | |
151 | for (i = 0; envp[i]; i++) { | |
152 | const char *key; | |
153 | int keylen; | |
154 | ||
155 | key = envp[i]; | |
156 | keylen = strlen(key); | |
4a231017 | 157 | |
4497fcbf | 158 | /* prevent loops in the scripts we execute */ |
eabfc973 | 159 | if (strncmp(key, "UDEVD_EVENT=", 12) == 0) { |
4497fcbf KS |
160 | dbg("seems that the event source is not the kernel, just exit"); |
161 | goto exit; | |
162 | } | |
163 | ||
d3c37635 | 164 | if (bufpos + keylen >= HOTPLUG_BUFFER_SIZE-1) { |
6b493a20 | 165 | err("environment buffer too small, probably not called by the kernel"); |
d3c37635 KS |
166 | continue; |
167 | } | |
168 | ||
4497fcbf | 169 | /* remember the SUBSYSTEM */ |
4a231017 | 170 | if (strncmp(key, "SUBSYSTEM=", 10) == 0) |
4497fcbf | 171 | subsystem = &key[10]; |
4a231017 KS |
172 | |
173 | dbg("add '%s' to env[%i] buffer", key, i); | |
174 | strcpy(&usend_msg.envbuf[bufpos], key); | |
175 | bufpos += keylen + 1; | |
176 | } | |
4497fcbf KS |
177 | /* older kernels passed the SUBSYSTEM only as the first argument */ |
178 | if (!subsystem && argc == 2) { | |
179 | bufpos += sprintf(&usend_msg.envbuf[bufpos], "SUBSYSTEM=%s", argv[1]) + 1; | |
180 | dbg("add 'SUBSYSTEM=%s' to env[%i] buffer from argv", argv[1], i); | |
4a231017 KS |
181 | } |
182 | ||
183 | usend_msg_len = offsetof(struct udevsend_msg, envbuf) + bufpos; | |
184 | dbg("usend_msg_len=%i", usend_msg_len); | |
0028653c | 185 | |
2f6cbd19 | 186 | /* If we can't send, try to start daemon and resend message */ |
5cab7caa KS |
187 | loop = SEND_WAIT_MAX_SECONDS * SEND_WAIT_LOOP_PER_SECOND; |
188 | while (--loop) { | |
4a231017 | 189 | retval = sendto(sock, &usend_msg, usend_msg_len, 0, (struct sockaddr *)&saddr, addrlen); |
2f6cbd19 KS |
190 | if (retval != -1) { |
191 | retval = 0; | |
28e169f0 | 192 | goto exit; |
2f6cbd19 | 193 | } |
28e169f0 | 194 | |
2f6cbd19 | 195 | if (errno != ECONNREFUSED) { |
6b493a20 | 196 | err("error sending message (%s)", strerror(errno)); |
28e169f0 | 197 | goto fallback; |
2f6cbd19 | 198 | } |
28e169f0 | 199 | |
2f6cbd19 | 200 | if (!started_daemon) { |
6b493a20 | 201 | info("try to start udevd daemon"); |
2f6cbd19 KS |
202 | retval = start_daemon(); |
203 | if (retval) { | |
e750d24b | 204 | dbg("error starting daemon"); |
28e169f0 | 205 | goto fallback; |
2f6cbd19 | 206 | } |
e750d24b | 207 | dbg("udevd daemon started"); |
2f6cbd19 | 208 | started_daemon = 1; |
53921bfa | 209 | } else { |
5cab7caa KS |
210 | dbg("retry to connect %d", SEND_WAIT_MAX_SECONDS * SEND_WAIT_LOOP_PER_SECOND - loop); |
211 | usleep(1000 * 1000 / SEND_WAIT_LOOP_PER_SECOND); | |
53921bfa | 212 | } |
7fafc032 | 213 | } |
28e169f0 KS |
214 | |
215 | fallback: | |
6b493a20 | 216 | err("unable to connect to event daemon, try to call udev directly"); |
4497fcbf | 217 | run_udev(subsystem); |
28e169f0 | 218 | |
33db4b8d | 219 | exit: |
28e169f0 KS |
220 | if (sock != -1) |
221 | close(sock); | |
222 | ||
7257cb18 KS |
223 | logging_close(); |
224 | ||
2f6cbd19 | 225 | return retval; |
7fafc032 | 226 | } |