Branch data Line data Source code
1 : : /*-
2 : : * Copyright (c) 2011-2012 Baptiste Daroussin <bapt@FreeBSD.org>
3 : : * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
4 : : * Copyright (c) 2011 Philippe Pepiot <phil@philpep.org>
5 : : * All rights reserved.
6 : : *
7 : : * Redistribution and use in source and binary forms, with or without
8 : : * modification, are permitted provided that the following conditions
9 : : * are met:
10 : : * 1. Redistributions of source code must retain the above copyright
11 : : * notice, this list of conditions and the following disclaimer
12 : : * in this position and unchanged.
13 : : * 2. Redistributions in binary form must reproduce the above copyright
14 : : * notice, this list of conditions and the following disclaimer in the
15 : : * documentation and/or other materials provided with the distribution.
16 : : *
17 : : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
18 : : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 : : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 : : * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
21 : : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 : : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 : : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 : : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 : : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 : : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 : : */
28 : :
29 : : #include "pkg_config.h"
30 : :
31 : : #include <sys/wait.h>
32 : : #ifdef HAVE_SYS_PROCCTL_H
33 : : #include <sys/procctl.h>
34 : : #endif
35 : :
36 : : #include <assert.h>
37 : : #include <errno.h>
38 : : #include <fcntl.h>
39 : : #include <paths.h>
40 : : #include <poll.h>
41 : : #include <spawn.h>
42 : : #include <stdlib.h>
43 : : #include <limits.h>
44 : : #include <string.h>
45 : : #include <xstring.h>
46 : :
47 : : #include "pkg.h"
48 : : #include "private/pkg.h"
49 : : #include "private/event.h"
50 : :
51 : : extern char **environ;
52 : :
53 : : int
54 : 2474 : pkg_script_run(struct pkg * const pkg, pkg_script type, bool upgrade)
55 : : {
56 : 2474 : xstring *script_cmd = NULL;
57 : : size_t i, j, script_len;
58 : : int error, pstat;
59 : : pid_t pid;
60 : : const char *script_cmd_p;
61 : : const char *argv[4];
62 : : char **ep;
63 : 2474 : int ret = EPKG_OK;
64 : 2474 : int fd = -1;
65 : 2474 : int stdin_pipe[2] = {-1, -1};
66 : : posix_spawn_file_actions_t action;
67 : 2474 : bool use_pipe = 0;
68 : 2474 : bool debug = false;
69 : : ssize_t bytes_written;
70 : : long argmax;
71 : 2474 : int cur_pipe[2] = {-1, -1};
72 : : #ifdef PROC_REAP_KILL
73 : : bool do_reap;
74 : : pid_t mypid;
75 : : struct procctl_reaper_status info;
76 : : struct procctl_reaper_kill killemall;
77 : : #endif
78 : : struct {
79 : : const char * const arg;
80 : : const pkg_script b;
81 : : const pkg_script a;
82 : 2474 : } const map[] = {
83 : : /* a implies b with argument arg */
84 : : {"PRE-INSTALL", PKG_SCRIPT_INSTALL, PKG_SCRIPT_PRE_INSTALL},
85 : : {"POST-INSTALL", PKG_SCRIPT_INSTALL, PKG_SCRIPT_POST_INSTALL},
86 : : {"DEINSTALL", PKG_SCRIPT_DEINSTALL, PKG_SCRIPT_PRE_DEINSTALL},
87 : : {"POST-DEINSTALL", PKG_SCRIPT_DEINSTALL, PKG_SCRIPT_POST_DEINSTALL},
88 : : };
89 : :
90 [ - + ]: 2474 : if (!pkg_object_bool(pkg_config_get("RUN_SCRIPTS"))) {
91 : 0 : return (EPKG_OK);
92 : : }
93 : :
94 [ - + ]: 4595 : for (i = 0; i < sizeof(map) / sizeof(map[0]); i++) {
95 [ + + ]: 4595 : if (map[i].a == type)
96 : 2474 : break;
97 : 2121 : }
98 : :
99 [ - + ]: 2474 : assert(i < sizeof(map) / sizeof(map[0]));
100 : :
101 : : #ifdef PROC_REAP_KILL
102 : 2474 : mypid = getpid();
103 : 2474 : do_reap = procctl(P_PID, mypid, PROC_REAP_ACQUIRE, NULL) == 0;
104 : : #endif
105 [ + + ]: 24740 : for (j = 0; j < PKG_NUM_SCRIPTS; j++) {
106 [ + + ]: 22266 : if (pkg_script_get(pkg, j) == NULL)
107 : 21786 : continue;
108 [ + + - + ]: 480 : if (j == map[i].a || j == map[i].b) {
109 [ - + ]: 201 : xstring_renew(script_cmd);
110 [ + + ]: 201 : if (upgrade) {
111 : 4 : setenv("PKG_UPGRADE", "true", 1);
112 : 4 : }
113 : 201 : setenv("PKG_NAME", pkg->name, 1);
114 : 201 : setenv("PKG_PREFIX", pkg->prefix, 1);
115 [ + + ]: 201 : if (ctx.pkg_rootdir == NULL)
116 : 103 : ctx.pkg_rootdir = "/";
117 : 201 : setenv("PKG_ROOTDIR", ctx.pkg_rootdir, 1);
118 : 201 : debug = pkg_object_bool(pkg_config_get("DEBUG_SCRIPTS"));
119 [ + - ]: 201 : if (debug)
120 : 0 : fprintf(script_cmd->fp, "set -x\n");
121 : 201 : pkg_fprintf(script_cmd->fp, "set -- %n-%v", pkg, pkg);
122 : :
123 [ + - ]: 201 : if (j == map[i].b) {
124 : : /* add arg **/
125 : 0 : fprintf(script_cmd->fp, " %s", map[i].arg);
126 : 0 : }
127 : :
128 : 201 : fprintf(script_cmd->fp, "\n%s", pkg->scripts[j]->buf);
129 : :
130 : : /* Determine the maximum argument length for the given
131 : : script to determine if /bin/sh -c can be used, or
132 : : if a pipe is required to /bin/sh -s. Similar to
133 : : find(1) determination */
134 [ + - ]: 201 : if ((argmax = sysconf(_SC_ARG_MAX)) == -1)
135 : 0 : argmax = _POSIX_ARG_MAX;
136 : 201 : argmax -= 1024;
137 [ + + ]: 19205 : for (ep = environ; *ep != NULL; ep++)
138 : 19004 : argmax -= strlen(*ep) + 1 + sizeof(*ep);
139 : 201 : argmax -= 1 + sizeof(*ep);
140 : :
141 : 201 : fflush(script_cmd->fp);
142 : 201 : script_len = strlen(script_cmd->buf);
143 : 201 : pkg_debug(3, "Scripts: executing\n--- BEGIN ---\n%s\nScripts: --- END ---", script_cmd->buf);
144 : 201 : posix_spawn_file_actions_init(&action);
145 [ + - ]: 201 : if (get_socketpair(cur_pipe) == -1) {
146 : 0 : pkg_emit_errno("pkg_script_run", "socketpair");
147 : 0 : goto cleanup;
148 : : }
149 : :
150 [ + - ]: 201 : if (fcntl(cur_pipe[0], F_SETFL, O_NONBLOCK) == -1) {
151 : 0 : pkg_emit_errno("pkg_script_run", "fcntl");
152 : 0 : goto cleanup;
153 : : }
154 : :
155 : 201 : setenv("PKG_MSGFD", "4", 1);
156 : :
157 : 201 : posix_spawn_file_actions_adddup2(&action, cur_pipe[1], 4);
158 : 201 : posix_spawn_file_actions_addclose(&action, cur_pipe[0]);
159 : : /*
160 : : * consider cur_pipe[1] to probably be the lastest
161 : : * opened fd close all unuseful fd up to there
162 : : */
163 [ + + ]: 1239 : for (int i = 5; i <= cur_pipe[1]; i++) {
164 [ + + ]: 1038 : if (i != cur_pipe[0])
165 : 837 : posix_spawn_file_actions_addclose(&action, i);
166 : 1038 : }
167 [ - + ]: 201 : if (script_len > argmax) {
168 [ # # ]: 0 : if (pipe(stdin_pipe) < 0) {
169 : 0 : ret = EPKG_FATAL;
170 : 0 : posix_spawn_file_actions_destroy(&action);
171 : 0 : goto cleanup;
172 : : }
173 : :
174 : 0 : posix_spawn_file_actions_adddup2(&action, stdin_pipe[0],
175 : : STDIN_FILENO);
176 : 0 : posix_spawn_file_actions_addclose(&action, stdin_pipe[1]);
177 : :
178 : 0 : argv[0] = _PATH_BSHELL;
179 : 0 : argv[1] = "-s";
180 : 0 : argv[2] = NULL;
181 : :
182 : 0 : use_pipe = 1;
183 : 0 : } else {
184 : 201 : fd = open("/dev/null", O_RDWR);
185 [ + - ]: 201 : if (fd < 0) {
186 : 0 : pkg_errno("Cannot open %s", "/dev/null");
187 : 0 : ret = EPKG_FATAL;
188 : 0 : posix_spawn_file_actions_destroy(&action);
189 : 0 : goto cleanup;
190 : : }
191 : 201 : posix_spawn_file_actions_adddup2(&action,
192 : 201 : fd, STDIN_FILENO);
193 : :
194 : 201 : argv[0] = _PATH_BSHELL;
195 : 201 : argv[1] = "-c";
196 : 201 : argv[2] = script_cmd->buf;
197 : 201 : argv[3] = NULL;
198 : :
199 : 201 : use_pipe = 0;
200 : : }
201 : :
202 [ + - + - ]: 402 : if ((error = posix_spawn(&pid, _PATH_BSHELL, &action,
203 : 201 : NULL, __DECONST(char **, argv),
204 : 402 : environ)) != 0) {
205 : 0 : errno = error;
206 : 0 : pkg_errno("Cannot runscript %s", map[i].arg);
207 : 0 : posix_spawn_file_actions_destroy(&action);
208 : 0 : goto cleanup;
209 : : }
210 : 201 : posix_spawn_file_actions_destroy(&action);
211 : :
212 [ - + ]: 201 : if (fd != -1)
213 : 201 : close(fd);
214 [ + - ]: 201 : if (use_pipe) {
215 : 0 : script_cmd_p = script_cmd->buf;
216 [ # # ]: 0 : while (script_len > 0) {
217 [ # # # # : 0 : if ((bytes_written = write(stdin_pipe[1], script_cmd_p,
# # ]
218 : 0 : script_len)) == -1) {
219 [ # # ]: 0 : if (errno == EINTR)
220 : 0 : continue;
221 : 0 : ret = EPKG_FATAL;
222 : 0 : goto cleanup;
223 : : }
224 : 0 : script_cmd_p += bytes_written;
225 : 0 : script_len -= bytes_written;
226 : : }
227 : 0 : close(stdin_pipe[1]);
228 : 0 : }
229 : :
230 : 201 : unsetenv("PKG_PREFIX");
231 : :
232 : 201 : close(cur_pipe[1]);
233 : 201 : cur_pipe[1] = -1;
234 : :
235 : 201 : ret = pkg_script_run_child(pid, &pstat, cur_pipe[0], map[i].arg);
236 : :
237 : 201 : close(cur_pipe[0]);
238 : 201 : cur_pipe[0] = -1;
239 : 201 : }
240 : 2954 : }
241 : :
242 : : cleanup:
243 : :
244 : 2474 : xstring_free(script_cmd);
245 [ + - ]: 2474 : if (stdin_pipe[0] != -1)
246 : 0 : close(stdin_pipe[0]);
247 [ + - ]: 2474 : if (stdin_pipe[1] != -1)
248 : 0 : close(stdin_pipe[1]);
249 [ + - ]: 2474 : if (cur_pipe[0] != -1)
250 : 0 : close(cur_pipe[0]);
251 [ + - ]: 2474 : if (cur_pipe[1] != -1)
252 : 0 : close(cur_pipe[1]);
253 : :
254 : : #ifdef PROC_REAP_KILL
255 : : /*
256 : : * If the prior PROCCTL_REAP_ACQUIRE call failed, the kernel
257 : : * probably doesn't support this, so don't try.
258 : : */
259 [ + - ]: 2474 : if (!do_reap)
260 : 0 : return (ret);
261 : :
262 : 2474 : procctl(P_PID, mypid, PROC_REAP_STATUS, &info);
263 [ + + ]: 2474 : if (info.rs_children != 0) {
264 : 4 : killemall.rk_sig = SIGKILL;
265 : 4 : killemall.rk_flags = 0;
266 [ + - ]: 4 : if (procctl(P_PID, mypid, PROC_REAP_KILL, &killemall) != 0) {
267 : 0 : pkg_errno("%s", "Fail to kill all processes");
268 : 0 : }
269 : 4 : }
270 : 2474 : procctl(P_PID, mypid, PROC_REAP_RELEASE, NULL);
271 : : #endif
272 : :
273 : 2474 : return (ret);
274 : 2474 : }
275 : :
276 : :
277 : : int
278 : 301 : pkg_script_run_child(int pid, int *pstat, int inputfd, const char* script_name) {
279 : : struct pollfd pfd;
280 : : bool wait_for_child;
281 : : char msgbuf[16384+1];
282 : :
283 : :
284 : 301 : memset(&pfd, 0, sizeof(pfd));
285 : 301 : pfd.events = POLLIN | POLLERR | POLLHUP;
286 : 301 : pfd.fd = inputfd;
287 : :
288 : : // Wait for child to exit, and read input, including all queued input on child exit.
289 : 301 : wait_for_child = true;
290 : 301 : do {
291 : 111533 : pfd.revents = 0;
292 : 111533 : errno = 0;
293 : : // Check if child is running, get exitstatus if newly terminated.
294 : 111533 : pid_t p = 0;
295 [ - + - + ]: 111533 : while (wait_for_child && (p = waitpid(pid, pstat, WNOHANG)) == -1) {
296 [ # # ]: 0 : if (errno != EINTR) {
297 : 0 : pkg_emit_error("waitpid() failed: %s",
298 : 0 : strerror(errno));
299 : 0 : return (EPKG_FATAL);
300 : : }
301 : : }
302 [ + + ]: 111533 : if (p > 0) {
303 : 301 : wait_for_child = false;
304 : 301 : }
305 : : // Check for input from child, but only wait for more if child is still running.
306 : : // Read/print all available input.
307 : : ssize_t readsize;
308 : 111533 : do {
309 : 111577 : readsize = 0;
310 : : int pres;
311 [ - + ]: 111577 : while ((pres = poll(&pfd, 1, wait_for_child ? 1000 : 0)) == -1) {
312 [ # # ]: 0 : if (errno != EINTR) {
313 : 0 : pkg_emit_error("poll() failed: %s",
314 : 0 : strerror(errno));
315 : 0 : return (EPKG_FATAL);
316 : : }
317 : : }
318 [ + + - + ]: 111577 : if (pres > 0 && pfd.revents & POLLIN) {
319 [ + - ]: 111569 : while ((readsize = read(inputfd, msgbuf, sizeof msgbuf - 1)) < 0) {
320 : : // MacOS gives us ECONNRESET on child exit
321 [ # # # # ]: 0 : if (errno == EAGAIN || errno == ECONNRESET) {
322 : 0 : break;
323 : : }
324 [ # # ]: 0 : if (errno != EINTR) {
325 : 0 : pkg_emit_errno(__func__, "read");
326 : 0 : return (EPKG_FATAL);
327 : : }
328 : : }
329 [ + + ]: 111569 : if (readsize > 0) {
330 : 44 : msgbuf[readsize] = '\0';
331 : 44 : pkg_emit_message(msgbuf);
332 : 44 : }
333 : 111569 : }
334 [ + + ]: 111577 : } while (readsize > 0);
335 [ + + ]: 111533 : } while (wait_for_child);
336 : :
337 [ + + ]: 301 : if (WEXITSTATUS(*pstat) != 0) {
338 [ - + ]: 29 : if (WEXITSTATUS(*pstat) == 3)
339 : 0 : exit(0);
340 : :
341 : 29 : pkg_emit_error("%s script failed", script_name);
342 : 29 : return (EPKG_FATAL);
343 : : }
344 : 272 : return (EPKG_OK);
345 : 301 : }
|