chiark / gitweb /
udev: fix netdev RUN handling
[elogind.git] / udevinitsend.c
1 /*
2  * udevinitsend.c
3  *
4  * Userspace devfs
5  *
6  * Copyright (C) 2004, 2005 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 <unistd.h>
27 #include <fcntl.h>
28 #include <errno.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <sys/mman.h>
33 #include <sys/socket.h>
34 #include <sys/wait.h>
35 #include <sys/un.h>
36 #include <dirent.h>
37
38 #include "udev.h"
39 #include "udev_version.h"
40 #include "udevd.h"
41 #include "logging.h"
42
43
44 #ifdef USE_LOG
45 void log_message (int level, const char *format, ...)
46 {
47         va_list args;
48
49         va_start(args, format);
50         vsyslog(level, format, args);
51         va_end(args);
52 }
53 #endif
54
55 /*
56  * udevsend
57  *
58  * Scan a file, write all variables into the msgbuf and
59  * fires the message to udevd.
60  */
61 static int udevsend(char *filename, int sock, int ignore_loops)
62 {
63         struct stat statbuf;
64         int fd, bufpos;
65         char *fdmap, *ls, *le, *ch;
66         struct udevd_msg usend_msg;
67         int retval = 0;
68         int usend_msg_len;
69         struct sockaddr_un saddr;
70         socklen_t addrlen;
71         
72         if (stat(filename,&statbuf) < 0) {
73                 dbg("cannot stat %s: %s\n", filename, strerror(errno));
74                 return 1;
75         }
76         fd = open(filename,O_RDONLY);
77         if (fd < 0)
78                 return 1;
79
80         fdmap = mmap(0, statbuf.st_size,
81                      PROT_READ, MAP_PRIVATE, fd, 0);
82         close(fd);
83         if (fdmap == MAP_FAILED) {
84                 dbg("mmap failed, errno %d\n", errno);
85                 return 1;
86         }
87
88         memset(&saddr, 0x00, sizeof(struct sockaddr_un));
89         saddr.sun_family = AF_LOCAL;
90         /* use abstract namespace for socket path */
91         strcpy(&saddr.sun_path[1], UDEVD_SOCK_PATH);
92         addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(saddr.sun_path+1) + 1;
93
94         memset(usend_msg.envbuf, 0, UEVENT_BUFFER_SIZE+256);
95         bufpos = 0;
96         memset(&usend_msg, 0x00, sizeof(struct udevd_msg));
97         strcpy(usend_msg.magic, UDEV_MAGIC);
98
99         ls = fdmap;
100         ch = le = ls;
101         while (*ch && ch < fdmap + statbuf.st_size) {
102                 le = strchr(ch,'\n');
103                 if (!le)
104                         break;
105                 ch = strchr(ch,'=');
106                 if (!ch)
107                         break;
108
109                 /* prevent loops in the scripts we execute */
110                 if (strncmp(ls, "UDEVD_EVENT=", 12) == 0) {
111                         if (!ignore_loops) {
112                                 dbg("event already handled by udev\n");
113                                 retval = -1;
114                                 break;
115                         } 
116                         goto loop_end;
117                 }
118
119                 /* omit shell-generated keys */
120                 if (ls[0] == '_' && ls[1] == '=') {
121                         goto loop_end;
122                 }
123
124                 if (ch < le) {
125
126                         strncpy(&usend_msg.envbuf[bufpos],ls,(ch - ls) + 1);
127                         bufpos += (ch - ls) + 1;
128                         if (ch[1] == '\'' && le[-1] == '\'') {
129                                 strncpy(&usend_msg.envbuf[bufpos],ch + 2, (le - ch) -3);
130                                 bufpos += (le - ch) - 3;
131                         } else {
132                                 strncpy(&usend_msg.envbuf[bufpos],ch, (le - ch));
133                                 bufpos += (le - ch);
134                         }
135                         bufpos++;
136                 }
137 loop_end:
138                 ch = le + 1;
139                 ls = ch;
140         }
141         munmap(fdmap, statbuf.st_size);
142
143         usend_msg_len = offsetof(struct udevd_msg, envbuf) + bufpos;
144         dbg("usend_msg_len=%i", usend_msg_len);
145
146         if (!retval) {
147                 retval = sendto(sock, &usend_msg, usend_msg_len, 0, (struct sockaddr *)&saddr, addrlen);
148                 if (retval < 0) {
149                         dbg("error sending message (%s)", strerror(errno));
150                 }
151         }
152                 
153         return retval;
154 }
155
156 int main(int argc, char *argv[], char *envp[])
157 {
158         static const char short_options[] = "d:f:lVh";
159         int option;
160         char *event_dir = NULL;
161         char *event_file = NULL;
162         DIR *dirstream;
163         struct dirent *direntry;
164         int retval = 1, ignore_loops = 0;
165         int sock;
166
167         logging_init("udevinitsend");
168         dbg("version %s", UDEV_VERSION);
169
170         /* get command line options */
171         while (1) {
172                 option = getopt(argc, argv, short_options);
173                 if (option == -1)
174                         break;
175
176                 dbg("option '%c': ", option);
177                 switch (option) {
178                 case 'd':
179                         dbg("scan directory %s\n", optarg);
180                         event_dir = optarg;
181                         break;
182
183                 case 'f':
184                         dbg("use event file %s\n", optarg);
185                         event_file = optarg;
186                         break;
187
188                 case 'l':
189                         dbg("ignoring loops\n");
190                         ignore_loops = 1;
191                         break;
192
193                 case 'V':
194                         printf("udevinitsend, version 0.1\n");
195                         return 0;
196
197                 case 'h':
198                         retval = 0;
199                 }
200         }
201
202         sock = socket(AF_LOCAL, SOCK_DGRAM, 0);
203         if (sock == -1) {
204                 dbg("error getting socket");
205                 return 1;
206         }
207
208         if (event_dir) {
209                 dirstream = opendir(event_dir);
210                 if (!dirstream) {
211                         info("error opening directory %s: %s\n",
212                              event_dir, strerror(errno));
213                         return 1;
214                 }
215                 chdir(event_dir);
216                 while ((direntry = readdir(dirstream)) != NULL) {
217                         if (!strcmp(direntry->d_name,".") ||
218                             !strcmp(direntry->d_name,".."))
219                                 continue;
220                         retval = udevsend(direntry->d_name, sock, ignore_loops);
221                 }
222                 closedir(dirstream);
223         } else if (event_file) {
224                 retval = udevsend(event_file, sock, ignore_loops);
225         }
226
227         if (sock != -1)
228                 close(sock);
229
230         return retval;
231 }