chiark / gitweb /
udevinfo: restore -d option
[elogind.git] / udevinitsend.c
1 /*
2  * udevinitsend.c
3  *
4  * Copyright (C) 2004, 2005 SuSE Linux Products GmbH
5  * Author:
6  *      Hannes Reinecke <hare@suse.de>
7  *
8  *      This program is free software; you can redistribute it and/or modify it
9  *      under the terms of the GNU General Public License as published by the
10  *      Free Software Foundation version 2 of the License.
11  * 
12  *      This program is distributed in the hope that it will be useful, but
13  *      WITHOUT ANY WARRANTY; without even the implied warranty of
14  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *      General Public License for more details.
16  * 
17  *      You should have received a copy of the GNU General Public License along
18  *      with this program; if not, write to the Free Software Foundation, Inc.,
19  *      675 Mass Ave, Cambridge, MA 02139, USA.
20  *
21  */
22
23 #include <stdio.h>
24 #include <stddef.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <errno.h>
30 #include <string.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <sys/mman.h>
34 #include <sys/socket.h>
35 #include <sys/wait.h>
36 #include <sys/un.h>
37 #include <dirent.h>
38
39 #include "udev.h"
40 #include "udev_version.h"
41 #include "udevd.h"
42 #include "udev_utils.h"
43 #include "logging.h"
44
45 static int log = 0;
46
47 #ifdef USE_LOG
48 void log_message (int priority, const char *format, ...)
49 {
50         va_list args;
51
52         if (priority > log)
53                 return;
54
55         va_start(args, format);
56         vsyslog(priority, format, args);
57         va_end(args);
58 }
59 #endif
60
61 /*
62  * udevsend
63  *
64  * Scan a file, write all variables into the msgbuf and
65  * fires the message to udevd.
66  */
67 static int udevsend(char *filename, int sock, int disable_loop_detection)
68 {
69         static struct udevd_msg usend_msg;
70         int usend_msg_len;
71         int bufpos = 0;
72         struct stat statbuf;
73         int fd;
74         char *fdmap, *ls, *le, *ch;
75         struct sockaddr_un saddr;
76         socklen_t addrlen;
77         int retval = 0;
78
79         if (stat(filename,&statbuf) < 0) {
80                 dbg("cannot stat %s: %s\n", filename, strerror(errno));
81                 return 1;
82         }
83         fd = open(filename,O_RDONLY);
84         if (fd < 0)
85                 return 1;
86
87         fdmap = mmap(0, statbuf.st_size,
88                      PROT_READ, MAP_PRIVATE, fd, 0);
89         close(fd);
90         if (fdmap == MAP_FAILED) {
91                 dbg("mmap failed, errno %d\n", errno);
92                 return 1;
93         }
94
95         memset(&saddr, 0x00, sizeof(struct sockaddr_un));
96         saddr.sun_family = AF_LOCAL;
97         /* use abstract namespace for socket path */
98         strcpy(&saddr.sun_path[1], UDEVD_SOCK_PATH);
99         addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(saddr.sun_path+1) + 1;
100
101         memset(&usend_msg, 0x00, sizeof(struct udevd_msg));
102         strcpy(usend_msg.magic, UDEV_MAGIC);
103         usend_msg.type = UDEVD_UEVENT_INITSEND;
104
105         ls = fdmap;
106         ch = le = ls;
107         while (*ch && ch < fdmap + statbuf.st_size) {
108                 le = strchr(ch, '\n');
109                 if (!le)
110                         break;
111                 ch = strchr(ch, '=');
112                 if (!ch)
113                         break;
114
115                 /* prevent loops in the scripts we execute */
116                 if (strncmp(ls, "UDEVD_EVENT=", 12) == 0) {
117                         if (!disable_loop_detection) {
118                                 dbg("event already handled by udev\n");
119                                 retval = -1;
120                                 break;
121                         } 
122                         goto loop_end;
123                 }
124
125                 /* omit shell-generated keys */
126                 if (ls[0] == '_' && ls[1] == '=') {
127                         goto loop_end;
128                 }
129
130                 if (ch < le) {
131                         strncpy(&usend_msg.envbuf[bufpos],ls,(ch - ls) + 1);
132                         bufpos += (ch - ls) + 1;
133                         if (ch[1] == '\'' && le[-1] == '\'') {
134                                 strncpy(&usend_msg.envbuf[bufpos],ch + 2, (le - ch) - 3);
135                                 bufpos += (le - ch) - 3;
136                         } else {
137                                 strncpy(&usend_msg.envbuf[bufpos],ch + 1, (le - ch) - 1);
138                                 bufpos += (le - ch) - 1;
139                         }
140                         bufpos++;
141                 }
142 loop_end:
143                 ch = le + 1;
144                 ls = ch;
145         }
146         munmap(fdmap, statbuf.st_size);
147
148         usend_msg_len = offsetof(struct udevd_msg, envbuf) + bufpos;
149         dbg("usend_msg_len=%i", usend_msg_len);
150
151         if (!retval) {
152                 retval = sendto(sock, &usend_msg, usend_msg_len, 0, (struct sockaddr *)&saddr, addrlen);
153                 if (retval < 0) {
154                         dbg("error sending message (%s)", strerror(errno));
155                         retval = -1;
156                 }
157         }
158
159         return retval;
160 }
161
162 int main(int argc, char *argv[], char *envp[])
163 {
164         static const char short_options[] = "d:f:lVh";
165         int option;
166         char *event_dir = NULL;
167         char *event_file = NULL;
168         DIR *dirstream;
169         struct dirent *direntry;
170         int retval = 0;
171         int disable_loop_detection = 0;
172         int sock;
173         const char *env;
174
175         env = getenv("UDEV_LOG");
176         if (env)
177                 log = log_priority(env);
178
179         logging_init("udevinitsend");
180         dbg("version %s", UDEV_VERSION);
181
182         /* get command line options */
183         while (1) {
184                 option = getopt(argc, argv, short_options);
185                 if (option == -1)
186                         break;
187
188                 dbg("option '%c': ", option);
189                 switch (option) {
190                 case 'd':
191                         dbg("scan directory %s\n", optarg);
192                         event_dir = optarg;
193                         break;
194
195                 case 'f':
196                         dbg("use event file %s\n", optarg);
197                         event_file = optarg;
198                         break;
199
200                 case 'l':
201                         dbg("disable loop detection, ignore UDEVD_EVENT\n");
202                         disable_loop_detection = 1;
203                         break;
204
205                 case 'h':
206                         retval = 0;
207                 }
208         }
209
210         sock = socket(AF_LOCAL, SOCK_DGRAM, 0);
211         if (sock == -1) {
212                 dbg("error getting socket");
213                 return 1;
214         }
215
216         if (event_dir) {
217                 dirstream = opendir(event_dir);
218                 if (!dirstream) {
219                         info("error opening directory %s: %s\n",
220                              event_dir, strerror(errno));
221                         return 2;
222                 }
223                 chdir(event_dir);
224                 while ((direntry = readdir(dirstream)) != NULL) {
225                         if (!strcmp(direntry->d_name,".") ||
226                             !strcmp(direntry->d_name,".."))
227                                 continue;
228                         retval = udevsend(direntry->d_name, sock, disable_loop_detection);
229                 }
230                 closedir(dirstream);
231         } else if (event_file) {
232                 retval = udevsend(event_file, sock, disable_loop_detection);
233         }
234
235         if (sock != -1)
236                 close(sock);
237
238         if (retval)
239                 return 3;
240         return 0;
241 }