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
pkg_script_run(struct pkg * const pkg,pkg_script type,bool upgrade)54 pkg_script_run(struct pkg * const pkg, pkg_script type, bool upgrade)
55 {
56 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 int ret = EPKG_OK;
64 int fd = -1;
65 int stdin_pipe[2] = {-1, -1};
66 posix_spawn_file_actions_t action;
67 bool use_pipe = 0;
68 bool debug = false;
69 ssize_t bytes_written;
70 long argmax;
71 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 } 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 if (!pkg_object_bool(pkg_config_get("RUN_SCRIPTS"))) {
91 return (EPKG_OK);
92 }
93
94 for (i = 0; i < sizeof(map) / sizeof(map[0]); i++) {
95 if (map[i].a == type)
96 break;
97 }
98
99 assert(i < sizeof(map) / sizeof(map[0]));
100
101 #ifdef PROC_REAP_KILL
102 mypid = getpid();
103 do_reap = procctl(P_PID, mypid, PROC_REAP_ACQUIRE, NULL) == 0;
104 #endif
105 for (j = 0; j < PKG_NUM_SCRIPTS; j++) {
106 if (pkg_script_get(pkg, j) == NULL)
107 continue;
108 if (j == map[i].a || j == map[i].b) {
109 xstring_renew(script_cmd);
110 if (upgrade) {
111 setenv("PKG_UPGRADE", "true", 1);
112 }
113 setenv("PKG_NAME", pkg->name, 1);
114 setenv("PKG_PREFIX", pkg->prefix, 1);
115 if (ctx.pkg_rootdir == NULL)
116 ctx.pkg_rootdir = "/";
117 setenv("PKG_ROOTDIR", ctx.pkg_rootdir, 1);
118 debug = pkg_object_bool(pkg_config_get("DEBUG_SCRIPTS"));
119 if (debug)
120 fprintf(script_cmd->fp, "set -x\n");
121 pkg_fprintf(script_cmd->fp, "set -- %n-%v", pkg, pkg);
122
123 if (j == map[i].b) {
124 /* add arg **/
125 fprintf(script_cmd->fp, " %s", map[i].arg);
126 }
127
128 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 if ((argmax = sysconf(_SC_ARG_MAX)) == -1)
135 argmax = _POSIX_ARG_MAX;
136 argmax -= 1024;
137 for (ep = environ; *ep != NULL; ep++)
138 argmax -= strlen(*ep) + 1 + sizeof(*ep);
139 argmax -= 1 + sizeof(*ep);
140
141 fflush(script_cmd->fp);
142 script_len = strlen(script_cmd->buf);
143 pkg_debug(3, "Scripts: executing\n--- BEGIN ---\n%s\nScripts: --- END ---", script_cmd->buf);
144 posix_spawn_file_actions_init(&action);
145 if (get_socketpair(cur_pipe) == -1) {
146 pkg_emit_errno("pkg_script_run", "socketpair");
147 goto cleanup;
148 }
149
150 if (fcntl(cur_pipe[0], F_SETFL, O_NONBLOCK) == -1) {
151 pkg_emit_errno("pkg_script_run", "fcntl");
152 goto cleanup;
153 }
154
155 setenv("PKG_MSGFD", "4", 1);
156
157 posix_spawn_file_actions_adddup2(&action, cur_pipe[1], 4);
158 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 for (int i = 5; i <= cur_pipe[1]; i++) {
164 if (i != cur_pipe[0])
165 posix_spawn_file_actions_addclose(&action, i);
166 }
167 if (script_len > argmax) {
168 if (pipe(stdin_pipe) < 0) {
169 ret = EPKG_FATAL;
170 posix_spawn_file_actions_destroy(&action);
171 goto cleanup;
172 }
173
174 posix_spawn_file_actions_adddup2(&action, stdin_pipe[0],
175 STDIN_FILENO);
176 posix_spawn_file_actions_addclose(&action, stdin_pipe[1]);
177
178 argv[0] = _PATH_BSHELL;
179 argv[1] = "-s";
180 argv[2] = NULL;
181
182 use_pipe = 1;
183 } else {
184 fd = open("/dev/null", O_RDWR);
185 if (fd < 0) {
186 pkg_errno("Cannot open %s", "/dev/null");
187 ret = EPKG_FATAL;
188 posix_spawn_file_actions_destroy(&action);
189 goto cleanup;
190 }
191 posix_spawn_file_actions_adddup2(&action,
192 fd, STDIN_FILENO);
193
194 argv[0] = _PATH_BSHELL;
195 argv[1] = "-c";
196 argv[2] = script_cmd->buf;
197 argv[3] = NULL;
198
199 use_pipe = 0;
200 }
201
202 if ((error = posix_spawn(&pid, _PATH_BSHELL, &action,
203 NULL, __DECONST(char **, argv),
204 environ)) != 0) {
205 errno = error;
206 pkg_errno("Cannot runscript %s", map[i].arg);
207 posix_spawn_file_actions_destroy(&action);
208 goto cleanup;
209 }
210 posix_spawn_file_actions_destroy(&action);
211
212 if (fd != -1)
213 close(fd);
214 if (use_pipe) {
215 script_cmd_p = script_cmd->buf;
216 while (script_len > 0) {
217 if ((bytes_written = write(stdin_pipe[1], script_cmd_p,
218 script_len)) == -1) {
219 if (errno == EINTR)
220 continue;
221 ret = EPKG_FATAL;
222 goto cleanup;
223 }
224 script_cmd_p += bytes_written;
225 script_len -= bytes_written;
226 }
227 close(stdin_pipe[1]);
228 }
229
230 unsetenv("PKG_PREFIX");
231
232 close(cur_pipe[1]);
233 cur_pipe[1] = -1;
234
235 ret = pkg_script_run_child(pid, &pstat, cur_pipe[0], map[i].arg);
236
237 close(cur_pipe[0]);
238 cur_pipe[0] = -1;
239 }
240 }
241
242 cleanup:
243
244 xstring_free(script_cmd);
245 if (stdin_pipe[0] != -1)
246 close(stdin_pipe[0]);
247 if (stdin_pipe[1] != -1)
248 close(stdin_pipe[1]);
249 if (cur_pipe[0] != -1)
250 close(cur_pipe[0]);
251 if (cur_pipe[1] != -1)
252 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 if (!do_reap)
260 return (ret);
261
262 procctl(P_PID, mypid, PROC_REAP_STATUS, &info);
263 if (info.rs_children != 0) {
264 killemall.rk_sig = SIGKILL;
265 killemall.rk_flags = 0;
266 if (procctl(P_PID, mypid, PROC_REAP_KILL, &killemall) != 0) {
267 pkg_errno("%s", "Fail to kill all processes");
268 }
269 }
270 procctl(P_PID, mypid, PROC_REAP_RELEASE, NULL);
271 #endif
272
273 return (ret);
274 }
275
276
277 int
pkg_script_run_child(int pid,int * pstat,int inputfd,const char * script_name)278 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 memset(&pfd, 0, sizeof(pfd));
285 pfd.events = POLLIN | POLLERR | POLLHUP;
286 pfd.fd = inputfd;
287
288 // Wait for child to exit, and read input, including all queued input on child exit.
289 wait_for_child = true;
290 do {
291 pfd.revents = 0;
292 errno = 0;
293 // Check if child is running, get exitstatus if newly terminated.
294 pid_t p = 0;
295 while (wait_for_child && (p = waitpid(pid, pstat, WNOHANG)) == -1) {
296 if (errno != EINTR) {
297 pkg_emit_error("waitpid() failed: %s",
298 strerror(errno));
299 return (EPKG_FATAL);
300 }
301 }
302 if (p > 0) {
303 wait_for_child = false;
304 }
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 do {
309 readsize = 0;
310 int pres;
311 while ((pres = poll(&pfd, 1, wait_for_child ? 1000 : 0)) == -1) {
312 if (errno != EINTR) {
313 pkg_emit_error("poll() failed: %s",
314 strerror(errno));
315 return (EPKG_FATAL);
316 }
317 }
318 if (pres > 0 && pfd.revents & POLLIN) {
319 while ((readsize = read(inputfd, msgbuf, sizeof msgbuf - 1)) < 0) {
320 // MacOS gives us ECONNRESET on child exit
321 if (errno == EAGAIN || errno == ECONNRESET) {
322 break;
323 }
324 if (errno != EINTR) {
325 pkg_emit_errno(__func__, "read");
326 return (EPKG_FATAL);
327 }
328 }
329 if (readsize > 0) {
330 msgbuf[readsize] = '\0';
331 pkg_emit_message(msgbuf);
332 }
333 }
334 } while (readsize > 0);
335 } while (wait_for_child);
336
337 if (WEXITSTATUS(*pstat) != 0) {
338 if (WEXITSTATUS(*pstat) == 3)
339 exit(0);
340
341 pkg_emit_error("%s script failed", script_name);
342 return (EPKG_FATAL);
343 }
344 return (EPKG_OK);
345 }
346