]> git.ipfire.org Git - thirdparty/systemd.git/blame - udev_utils_run.c
add udev_rules_run() to handle RUN list
[thirdparty/systemd.git] / udev_utils_run.c
CommitLineData
59d6bfef 1/*
59d6bfef
KS
2 * Copyright (C) 2004-2005 Kay Sievers <kay.sievers@vrfy.org>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation version 2 of the License.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
27b77df4 15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
59d6bfef
KS
16 *
17 */
18
19
20#include <stdlib.h>
21#include <stdio.h>
22#include <stddef.h>
23#include <unistd.h>
24#include <fcntl.h>
25#include <errno.h>
26#include <ctype.h>
fb819f55 27#include <syslog.h>
59d6bfef
KS
28#include <sys/socket.h>
29#include <sys/un.h>
30#include <sys/wait.h>
27f877e6 31#include <sys/select.h>
59d6bfef 32
59d6bfef 33#include "udev.h"
59d6bfef 34
aaa14841 35extern char **environ;
59d6bfef
KS
36
37int pass_env_to_socket(const char *sockname, const char *devpath, const char *action)
38{
39 int sock;
40 struct sockaddr_un saddr;
41 socklen_t addrlen;
42 char buf[2048];
43 size_t bufpos = 0;
44 int i;
40caaeec
KS
45 ssize_t count;
46 int retval = 0;
59d6bfef
KS
47
48 dbg("pass environment to socket '%s'", sockname);
49 sock = socket(AF_LOCAL, SOCK_DGRAM, 0);
50 memset(&saddr, 0x00, sizeof(struct sockaddr_un));
51 saddr.sun_family = AF_LOCAL;
d8a57e7c 52 /* abstract namespace only */
59d6bfef
KS
53 strcpy(&saddr.sun_path[1], sockname);
54 addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(saddr.sun_path+1) + 1;
55
56 bufpos = snprintf(buf, sizeof(buf)-1, "%s@%s", action, devpath);
57 bufpos++;
58 for (i = 0; environ[i] != NULL && bufpos < sizeof(buf); i++) {
59 bufpos += strlcpy(&buf[bufpos], environ[i], sizeof(buf) - bufpos-1);
60 bufpos++;
61 }
62
40caaeec
KS
63 count = sendto(sock, &buf, bufpos, 0, (struct sockaddr *)&saddr, addrlen);
64 if (count < 0)
65 retval = -1;
66 info("passed %zi bytes to socket '%s', ", count, sockname);
59d6bfef
KS
67
68 close(sock);
69 return retval;
70}
71
27f877e6 72int run_program(const char *command, const char *subsystem,
fb819f55 73 char *result, size_t ressize, size_t *reslen)
59d6bfef 74{
59d6bfef 75 int status;
27f877e6
KS
76 int outpipe[2] = {-1, -1};
77 int errpipe[2] = {-1, -1};
59d6bfef 78 pid_t pid;
59d6bfef 79 char arg[PATH_SIZE];
aab4c0ee 80 char program[PATH_SIZE];
59d6bfef
KS
81 char *argv[(sizeof(arg) / 2) + 1];
82 int devnull;
83 int i;
fb819f55 84 int retval = 0;
59d6bfef 85
36af2ddc 86 /* build argv from comand */
59d6bfef
KS
87 strlcpy(arg, command, sizeof(arg));
88 i = 0;
36af2ddc 89 if (strchr(arg, ' ') != NULL) {
40caaeec 90 char *pos = arg;
36af2ddc 91
59d6bfef
KS
92 while (pos != NULL) {
93 if (pos[0] == '\'') {
94 /* don't separate if in apostrophes */
95 pos++;
96 argv[i] = strsep(&pos, "\'");
36af2ddc 97 while (pos != NULL && pos[0] == ' ')
59d6bfef
KS
98 pos++;
99 } else {
100 argv[i] = strsep(&pos, " ");
101 }
102 dbg("arg[%i] '%s'", i, argv[i]);
103 i++;
104 }
27f877e6 105 argv[i] = NULL;
59d6bfef
KS
106 } else {
107 argv[0] = arg;
36af2ddc 108 argv[1] = NULL;
59d6bfef 109 }
36af2ddc 110 info("'%s'", command);
59d6bfef 111
27f877e6 112 /* prepare pipes from child to parent */
fb819f55 113 if (result != NULL || udev_log_priority >= LOG_INFO) {
27f877e6 114 if (pipe(outpipe) != 0) {
ff3e4bed 115 err("pipe failed: %s", strerror(errno));
27f877e6
KS
116 return -1;
117 }
118 }
fb819f55 119 if (udev_log_priority >= LOG_INFO) {
27f877e6 120 if (pipe(errpipe) != 0) {
ff3e4bed 121 err("pipe failed: %s", strerror(errno));
59d6bfef
KS
122 return -1;
123 }
124 }
125
aab4c0ee
KS
126 /* allow programs in /lib/udev called without the path */
127 if (strchr(argv[0], '/') == NULL) {
128 strlcpy(program, "/lib/udev/", sizeof(program));
129 strlcat(program, argv[0], sizeof(program));
130 argv[0] = program;
131 }
132
59d6bfef
KS
133 pid = fork();
134 switch(pid) {
135 case 0:
27f877e6 136 /* child closes parent ends of pipes */
f1ff8d7b
KS
137 if (outpipe[READ_END] > 0)
138 close(outpipe[READ_END]);
139 if (errpipe[READ_END] > 0)
140 close(errpipe[READ_END]);
27f877e6
KS
141
142 /* discard child output or connect to pipe */
59d6bfef 143 devnull = open("/dev/null", O_RDWR);
af5461f7
KS
144 if (devnull > 0) {
145 dup2(devnull, STDIN_FILENO);
f1ff8d7b 146 if (outpipe[WRITE_END] < 0)
af5461f7 147 dup2(devnull, STDOUT_FILENO);
f1ff8d7b 148 if (errpipe[WRITE_END] < 0)
af5461f7
KS
149 dup2(devnull, STDERR_FILENO);
150 close(devnull);
151 } else
ff3e4bed 152 err("open /dev/null failed: %s", strerror(errno));
b83b2991 153 if (outpipe[WRITE_END] > 0) {
f1ff8d7b 154 dup2(outpipe[WRITE_END], STDOUT_FILENO);
b83b2991
MI
155 close(outpipe[WRITE_END]);
156 }
157 if (errpipe[WRITE_END] > 0) {
f1ff8d7b 158 dup2(errpipe[WRITE_END], STDERR_FILENO);
b83b2991
MI
159 close(errpipe[WRITE_END]);
160 }
40caaeec 161 execv(argv[0], argv);
9b2e2d4a 162 if (errno == ENOENT || errno == ENOTDIR) {
8246d00d
SJR
163 /* may be on a filesytem which is not mounted right now */
164 info("program '%s' not found", argv[0]);
165 } else {
166 /* other problems */
167 err("exec of program '%s' failed", argv[0]);
168 }
59d6bfef
KS
169 _exit(1);
170 case -1:
ff3e4bed 171 err("fork of '%s' failed: %s", argv[0], strerror(errno));
59d6bfef
KS
172 return -1;
173 default:
27f877e6 174 /* read from child if requested */
f1ff8d7b 175 if (outpipe[READ_END] > 0 || errpipe[READ_END] > 0) {
853ccc43 176 ssize_t count;
27f877e6
KS
177 size_t respos = 0;
178
179 /* parent closes child ends of pipes */
f1ff8d7b
KS
180 if (outpipe[WRITE_END] > 0)
181 close(outpipe[WRITE_END]);
182 if (errpipe[WRITE_END] > 0)
183 close(errpipe[WRITE_END]);
27f877e6
KS
184
185 /* read child output */
f1ff8d7b 186 while (outpipe[READ_END] > 0 || errpipe[READ_END] > 0) {
27f877e6
KS
187 int fdcount;
188 fd_set readfds;
189
190 FD_ZERO(&readfds);
f1ff8d7b
KS
191 if (outpipe[READ_END] > 0)
192 FD_SET(outpipe[READ_END], &readfds);
193 if (errpipe[READ_END] > 0)
194 FD_SET(errpipe[READ_END], &readfds);
195 fdcount = select(UDEV_MAX(outpipe[READ_END], errpipe[READ_END])+1, &readfds, NULL, NULL, NULL);
27f877e6
KS
196 if (fdcount < 0) {
197 if (errno == EINTR)
198 continue;
59d6bfef
KS
199 retval = -1;
200 break;
201 }
202
27f877e6 203 /* get stdout */
f1ff8d7b 204 if (outpipe[READ_END] > 0 && FD_ISSET(outpipe[READ_END], &readfds)) {
27f877e6 205 char inbuf[1024];
40caaeec
KS
206 char *pos;
207 char *line;
59d6bfef 208
f1ff8d7b 209 count = read(outpipe[READ_END], inbuf, sizeof(inbuf)-1);
27f877e6 210 if (count <= 0) {
f1ff8d7b
KS
211 close(outpipe[READ_END]);
212 outpipe[READ_END] = -1;
27f877e6 213 if (count < 0) {
ff3e4bed 214 err("stdin read failed: %s", strerror(errno));
27f877e6
KS
215 retval = -1;
216 }
217 continue;
218 }
219 inbuf[count] = '\0';
27f877e6 220
40caaeec 221 /* store result for rule processing */
27f877e6 222 if (result) {
40caaeec
KS
223 if (respos + count < ressize) {
224 memcpy(&result[respos], inbuf, count);
225 respos += count;
226 } else {
27f877e6
KS
227 err("ressize %ld too short", (long)ressize);
228 retval = -1;
27f877e6 229 }
27f877e6 230 }
40caaeec
KS
231 pos = inbuf;
232 while ((line = strsep(&pos, "\n")))
233 if (pos || line[0] != '\0')
234 info("'%s' (stdout) '%s'", argv[0], line);
27f877e6
KS
235 }
236
237 /* get stderr */
f1ff8d7b 238 if (errpipe[READ_END] > 0 && FD_ISSET(errpipe[READ_END], &readfds)) {
27f877e6 239 char errbuf[1024];
40caaeec
KS
240 char *pos;
241 char *line;
27f877e6 242
f1ff8d7b 243 count = read(errpipe[READ_END], errbuf, sizeof(errbuf)-1);
27f877e6 244 if (count <= 0) {
f1ff8d7b
KS
245 close(errpipe[READ_END]);
246 errpipe[READ_END] = -1;
27f877e6 247 if (count < 0)
ff3e4bed 248 err("stderr read failed: %s", strerror(errno));
27f877e6
KS
249 continue;
250 }
251 errbuf[count] = '\0';
40caaeec
KS
252 pos = errbuf;
253 while ((line = strsep(&pos, "\n")))
254 if (pos || line[0] != '\0')
255 info("'%s' (stderr) '%s'", argv[0], line);
59d6bfef
KS
256 }
257 }
f1ff8d7b
KS
258 if (outpipe[READ_END] > 0)
259 close(outpipe[READ_END]);
260 if (errpipe[READ_END] > 0)
261 close(errpipe[READ_END]);
27f877e6
KS
262
263 /* return the childs stdout string */
264 if (result) {
265 result[respos] = '\0';
266 dbg("result='%s'", result);
267 if (reslen)
268 *reslen = respos;
269 }
59d6bfef
KS
270 }
271 waitpid(pid, &status, 0);
40caaeec
KS
272 if (WIFEXITED(status)) {
273 info("'%s' returned with status %i", argv[0], WEXITSTATUS(status));
274 if (WEXITSTATUS(status) != 0)
275 retval = -1;
276 } else {
277 err("'%s' abnormal exit", argv[0]);
59d6bfef
KS
278 retval = -1;
279 }
280 }
281
282 return retval;
283}