Branch data Line data Source code
1 : : /*-
2 : : * Copyright (c) 2019 Baptiste Daroussin <bapt@FreeBSD.org>
3 : : * All rights reserved.
4 : : *
5 : : * Redistribution and use in source and binary forms, with or without
6 : : * modification, are permitted provided that the following conditions
7 : : * are met:
8 : : * 1. Redistributions of source code must retain the above copyright
9 : : * notice, this list of conditions and the following disclaimer
10 : : * in this position and unchanged.
11 : : * 2. Redistributions in binary form must reproduce the above copyright
12 : : * notice, this list of conditions and the following disclaimer in the
13 : : * documentation and/or other materials provided with the distribution.
14 : : *
15 : : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16 : : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 : : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 : : * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19 : : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 : : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 : : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 : : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 : : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 : : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 : : */
26 : :
27 : : #include "pkg_config.h"
28 : :
29 : : #ifdef HAVE_SYS_PROCCTL_H
30 : : #include <sys/procctl.h>
31 : : #endif
32 : :
33 : : #include <sys/types.h>
34 : : #include <sys/wait.h>
35 : :
36 : : #include <errno.h>
37 : : #include <poll.h>
38 : : #include <xstring.h>
39 : : #include <err.h>
40 : : #include <stdio.h>
41 : :
42 : : #include "pkg.h"
43 : : #include "private/pkg.h"
44 : : #include "private/event.h"
45 : : #include "private/lua.h"
46 : :
47 : : extern char **environ;
48 : :
49 : : int
50 : 564 : pkg_lua_script_run(struct pkg * const pkg, pkg_lua_script type, bool upgrade)
51 : : {
52 : 564 : int ret = EPKG_OK;
53 : : int pstat;
54 : : #ifdef PROC_REAP_KILL
55 : : bool do_reap;
56 : : pid_t mypid;
57 : : struct procctl_reaper_status info;
58 : : struct procctl_reaper_kill killemall;
59 : : #endif
60 : : int cur_pipe[2];
61 : 564 : char *line = NULL;
62 : :
63 [ + + ]: 564 : if (tll_length(pkg->lua_scripts[type]) == 0)
64 : 542 : return (EPKG_OK);
65 : :
66 [ - + ]: 22 : if (!pkg_object_bool(pkg_config_get("RUN_SCRIPTS"))) {
67 : 0 : return (EPKG_OK);
68 : : }
69 : :
70 : : #ifdef PROC_REAP_KILL
71 : 22 : mypid = getpid();
72 : 22 : do_reap = procctl(P_PID, mypid, PROC_REAP_ACQUIRE, NULL) == 0;
73 : : #endif
74 : :
75 [ + - + + : 47 : tll_foreach(pkg->lua_scripts[type], s) {
+ + ]
76 [ - + ]: 25 : if (get_socketpair(cur_pipe) == -1) {
77 : 0 : pkg_emit_errno("pkg_lua_script_script", "socketpair");
78 : 0 : goto cleanup;
79 : : }
80 : 25 : pid_t pid = fork();
81 [ - + ]: 25 : if (pid == 0) {
82 : : static const luaL_Reg pkg_lib[] = {
83 : : { "print_msg", lua_print_msg },
84 : : { "prefixed_path", lua_prefix_path },
85 : : { "filecmp", lua_pkg_filecmp },
86 : : { "copy", lua_pkg_copy },
87 : : { "stat", lua_stat },
88 : : { "readdir", lua_readdir },
89 : : { "exec", lua_exec },
90 : : { "symlink", lua_pkg_symlink },
91 : : { NULL, NULL },
92 : : };
93 : 0 : close(cur_pipe[0]);
94 : 0 : lua_State *L = luaL_newstate();
95 : 0 : luaL_openlibs( L );
96 : 0 : lua_atpanic(L, (lua_CFunction)stack_dump );
97 : 0 : lua_pushinteger(L, cur_pipe[1]);
98 : 0 : lua_setglobal(L, "msgfd");
99 : 0 : lua_pushlightuserdata(L, pkg);
100 : 0 : lua_setglobal(L, "package");
101 : 0 : lua_pushinteger(L, pkg->rootfd);
102 : 0 : lua_setglobal(L, "rootfd");
103 : 0 : lua_pushstring(L, pkg->prefix);
104 : 0 : lua_setglobal(L, "pkg_prefix");
105 : 0 : lua_pushstring(L, pkg->name);
106 : 0 : lua_setglobal(L, "pkg_name");
107 : 0 : if (ctx.pkg_rootdir == NULL)
108 : 0 : ctx.pkg_rootdir = "/";
109 : 0 : lua_pushstring(L, ctx.pkg_rootdir);
110 : 0 : lua_setglobal(L, "pkg_rootdir");
111 : 0 : lua_pushboolean(L, (upgrade));
112 : 0 : lua_setglobal(L, "pkg_upgrade");
113 : 0 : luaL_newlib(L, pkg_lib);
114 : 0 : lua_setglobal(L, "pkg");
115 : 0 : lua_override_ios(L, true);
116 : :
117 : : /* parse and set arguments of the line is in the comments */
118 : 0 : if (STARTS_WITH(s->item, "-- args: ")) {
119 : 0 : char *walk, *begin, *line = NULL;
120 : 0 : int spaces, argc = 0;
121 : 0 : char **args = NULL;
122 : :
123 : 0 : walk = strchr(s->item, '\n');
124 : 0 : begin = s->item + strlen("-- args: ");
125 : 0 : line = xstrndup(begin, walk - begin);
126 : 0 : spaces = pkg_utils_count_spaces(line);
127 : 0 : args = xmalloc((spaces + 1)* sizeof(char *));
128 : 0 : walk = xstrdup(line);
129 [ # # ]: 0 : while (walk != NULL) {
130 : 0 : args[argc++] = pkg_utils_tokenize(&walk);
131 : : }
132 : 0 : lua_args_table(L, args, argc);
133 : 0 : }
134 : :
135 : 0 : pkg_debug(3, "Scripts: executing lua\n--- BEGIN ---\n%s\nScripts: --- END ---", s->item);
136 : 0 : if (luaL_dostring(L, s->item)) {
137 : 0 : pkg_emit_error("Failed to execute lua script: %s", lua_tostring(L, -1));
138 : 0 : lua_close(L);
139 : 0 : _exit(1);
140 : : }
141 : :
142 [ # # ]: 0 : if (lua_tonumber(L, -1) != 0) {
143 : 0 : lua_close(L);
144 : 0 : _exit(1);
145 : : }
146 : :
147 : 0 : lua_close(L);
148 : 0 : _exit(0);
149 [ - + ]: 25 : } else if (pid < 0) {
150 : 0 : pkg_emit_errno("Cannot fork", "lua_script");
151 : 0 : ret = EPKG_FATAL;
152 : 0 : goto cleanup;
153 : : }
154 : :
155 : 25 : close(cur_pipe[1]);
156 : :
157 : 25 : ret = pkg_script_run_child(pid, &pstat, cur_pipe[0], "lua");
158 : 47 : }
159 : :
160 : :
161 : : cleanup:
162 : : #ifdef PROC_REAP_KILL
163 : : /*
164 : : * If the prior PROCCTL_REAP_ACQUIRE call failed, the kernel
165 : : * probably doesn't support this, so don't try.
166 : : */
167 [ - + ]: 22 : if (!do_reap)
168 : 0 : return (ret);
169 : :
170 : 22 : procctl(P_PID, mypid, PROC_REAP_STATUS, &info);
171 : 22 : if (info.rs_children != 0) {
172 : 0 : killemall.rk_sig = SIGKILL;
173 : 0 : killemall.rk_flags = 0;
174 : 0 : if (procctl(P_PID, mypid, PROC_REAP_KILL, &killemall) != 0) {
175 : 0 : pkg_errno("%s", "Fail to kill all processes");
176 : 0 : }
177 : 0 : }
178 : 22 : procctl(P_PID, mypid, PROC_REAP_RELEASE, NULL);
179 : : #endif
180 : 22 : free(line);
181 : :
182 : 22 : return (ret);
183 : 564 : }
184 : :
185 : : ucl_object_t *
186 : 21 : pkg_lua_script_to_ucl(stringlist_t *scripts)
187 : : {
188 : : ucl_object_t *array;
189 : :
190 : 21 : array = ucl_object_typed_new(UCL_ARRAY);
191 [ + - + + : 45 : tll_foreach(*scripts, s)
+ + ]
192 : 48 : ucl_array_append(array, ucl_object_fromstring_common(s->item,
193 : 24 : strlen(s->item), UCL_STRING_RAW|UCL_STRING_TRIM));
194 : :
195 : 21 : return (array);
196 : : }
197 : :
198 : : int
199 : 64 : pkg_lua_script_from_ucl(struct pkg *pkg, const ucl_object_t *obj, pkg_lua_script type)
200 : : {
201 : : const ucl_object_t *cur;
202 : 64 : ucl_object_iter_t it = NULL;
203 : :
204 [ + + ]: 136 : while ((cur = ucl_iterate_object(obj, &it, true))) {
205 [ - + ]: 72 : if (ucl_object_type(cur) != UCL_STRING) {
206 : 0 : pkg_emit_error("lua scripts be strings");
207 : 0 : return (EPKG_FATAL);
208 : : }
209 [ + + ]: 72 : tll_push_back(pkg->lua_scripts[type], xstrdup(ucl_object_tostring(cur)));
210 : : }
211 : 64 : return (EPKG_OK);
212 : 64 : }
213 : :
|