]>
git.ipfire.org Git - thirdparty/systemd.git/blob - udev_utils_run.c
2 * udev_utils_run.c - execute programs from udev and read its output
4 * Copyright (C) 2004-2005 Kay Sievers <kay.sievers@vrfy.org>
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation version 2 of the License.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 675 Mass Ave, Cambridge, MA 02139, USA.
29 #include <sys/socket.h>
32 #include <sys/select.h>
36 extern char **environ
;
38 int pass_env_to_socket(const char *sockname
, const char *devpath
, const char *action
)
41 struct sockaddr_un saddr
;
49 dbg("pass environment to socket '%s'", sockname
);
50 sock
= socket(AF_LOCAL
, SOCK_DGRAM
, 0);
51 memset(&saddr
, 0x00, sizeof(struct sockaddr_un
));
52 saddr
.sun_family
= AF_LOCAL
;
53 /* abstract namespace only */
54 strcpy(&saddr
.sun_path
[1], sockname
);
55 addrlen
= offsetof(struct sockaddr_un
, sun_path
) + strlen(saddr
.sun_path
+1) + 1;
57 bufpos
= snprintf(buf
, sizeof(buf
)-1, "%s@%s", action
, devpath
);
59 for (i
= 0; environ
[i
] != NULL
&& bufpos
< sizeof(buf
); i
++) {
60 bufpos
+= strlcpy(&buf
[bufpos
], environ
[i
], sizeof(buf
) - bufpos
-1);
64 count
= sendto(sock
, &buf
, bufpos
, 0, (struct sockaddr
*)&saddr
, addrlen
);
67 info("passed %zi bytes to socket '%s', ", count
, sockname
);
73 int run_program(const char *command
, const char *subsystem
,
74 char *result
, size_t ressize
, size_t *reslen
, int log
)
78 int outpipe
[2] = {-1, -1};
79 int errpipe
[2] = {-1, -1};
82 char program
[PATH_SIZE
];
83 char *argv
[(sizeof(arg
) / 2) + 1];
87 /* build argv from comand */
88 strlcpy(arg
, command
, sizeof(arg
));
90 if (strchr(arg
, ' ') != NULL
) {
95 /* don't separate if in apostrophes */
97 argv
[i
] = strsep(&pos
, "\'");
98 while (pos
!= NULL
&& pos
[0] == ' ')
101 argv
[i
] = strsep(&pos
, " ");
103 dbg("arg[%i] '%s'", i
, argv
[i
]);
111 info("'%s'", command
);
113 /* prepare pipes from child to parent */
115 if (pipe(outpipe
) != 0) {
116 err("pipe failed: %s", strerror(errno
));
121 if (pipe(errpipe
) != 0) {
122 err("pipe failed: %s", strerror(errno
));
127 /* allow programs in /lib/udev called without the path */
128 if (strchr(argv
[0], '/') == NULL
) {
129 strlcpy(program
, "/lib/udev/", sizeof(program
));
130 strlcat(program
, argv
[0], sizeof(program
));
137 /* child closes parent ends of pipes */
138 if (outpipe
[READ_END
] > 0)
139 close(outpipe
[READ_END
]);
140 if (errpipe
[READ_END
] > 0)
141 close(errpipe
[READ_END
]);
143 /* discard child output or connect to pipe */
144 devnull
= open("/dev/null", O_RDWR
);
146 dup2(devnull
, STDIN_FILENO
);
147 if (outpipe
[WRITE_END
] < 0)
148 dup2(devnull
, STDOUT_FILENO
);
149 if (errpipe
[WRITE_END
] < 0)
150 dup2(devnull
, STDERR_FILENO
);
153 err("open /dev/null failed: %s", strerror(errno
));
154 if (outpipe
[WRITE_END
] > 0)
155 dup2(outpipe
[WRITE_END
], STDOUT_FILENO
);
156 if (errpipe
[WRITE_END
] > 0)
157 dup2(errpipe
[WRITE_END
], STDERR_FILENO
);
158 execv(argv
[0], argv
);
160 /* we should never reach this */
161 err("exec of program '%s' failed", argv
[0]);
164 err("fork of '%s' failed: %s", argv
[0], strerror(errno
));
167 /* read from child if requested */
168 if (outpipe
[READ_END
] > 0 || errpipe
[READ_END
] > 0) {
172 /* parent closes child ends of pipes */
173 if (outpipe
[WRITE_END
] > 0)
174 close(outpipe
[WRITE_END
]);
175 if (errpipe
[WRITE_END
] > 0)
176 close(errpipe
[WRITE_END
]);
178 /* read child output */
179 while (outpipe
[READ_END
] > 0 || errpipe
[READ_END
] > 0) {
184 if (outpipe
[READ_END
] > 0)
185 FD_SET(outpipe
[READ_END
], &readfds
);
186 if (errpipe
[READ_END
] > 0)
187 FD_SET(errpipe
[READ_END
], &readfds
);
188 fdcount
= select(UDEV_MAX(outpipe
[READ_END
], errpipe
[READ_END
])+1, &readfds
, NULL
, NULL
, NULL
);
197 if (outpipe
[READ_END
] > 0 && FD_ISSET(outpipe
[READ_END
], &readfds
)) {
202 count
= read(outpipe
[READ_END
], inbuf
, sizeof(inbuf
)-1);
204 close(outpipe
[READ_END
]);
205 outpipe
[READ_END
] = -1;
207 err("stdin read failed: %s", strerror(errno
));
214 /* store result for rule processing */
216 if (respos
+ count
< ressize
) {
217 memcpy(&result
[respos
], inbuf
, count
);
220 err("ressize %ld too short", (long)ressize
);
225 while ((line
= strsep(&pos
, "\n")))
226 if (pos
|| line
[0] != '\0')
227 info("'%s' (stdout) '%s'", argv
[0], line
);
231 if (errpipe
[READ_END
] > 0 && FD_ISSET(errpipe
[READ_END
], &readfds
)) {
236 count
= read(errpipe
[READ_END
], errbuf
, sizeof(errbuf
)-1);
238 close(errpipe
[READ_END
]);
239 errpipe
[READ_END
] = -1;
241 err("stderr read failed: %s", strerror(errno
));
244 errbuf
[count
] = '\0';
246 while ((line
= strsep(&pos
, "\n")))
247 if (pos
|| line
[0] != '\0')
248 info("'%s' (stderr) '%s'", argv
[0], line
);
251 if (outpipe
[READ_END
] > 0)
252 close(outpipe
[READ_END
]);
253 if (errpipe
[READ_END
] > 0)
254 close(errpipe
[READ_END
]);
256 /* return the childs stdout string */
258 result
[respos
] = '\0';
259 dbg("result='%s'", result
);
264 waitpid(pid
, &status
, 0);
265 if (WIFEXITED(status
)) {
266 info("'%s' returned with status %i", argv
[0], WEXITSTATUS(status
));
267 if (WEXITSTATUS(status
) != 0)
270 err("'%s' abnormal exit", argv
[0]);