6 #define _RPMSQ_INTERNAL
9 #include <rpm/rpmfileutil.h>
10 #include <rpm/rpmmacro.h>
11 #include <rpm/rpmio.h>
12 #include <rpm/rpmlog.h>
13 #include <rpm/rpmsw.h>
14 #include <rpm/header.h>
16 #include "rpmio/rpmlua.h"
17 #include "lib/rpmscript.h"
22 * Run internal Lua script.
24 static rpmRC runLuaScript(rpmts ts, ARGV_const_t prefixes,
25 const char *sname, rpmlogLvl lvl,
26 ARGV_t * argvp, const char *script, int arg1, int arg2)
28 rpmRC rc = RPMRC_FAIL;
32 ARGV_t argv = argvp ? *argvp : NULL;
33 rpmlua lua = NULL; /* Global state. */
36 rpmlog(RPMLOG_DEBUG, "%s: running <lua> scriptlet.\n", sname);
37 if (!rpmtsChrootDone(ts)) {
38 const char *rootDir = rpmtsRootDir(ts);
40 rootFd = open(".", O_RDONLY, 0);
42 if (rootDir != NULL && !rstreq(rootDir, "/") && *rootDir == '/')
44 xx = rpmtsSetChrootDone(ts, 1);
48 /* Create arg variable */
49 rpmluaPushTable(lua, "arg");
51 rpmluavSetListMode(var, 1);
54 for (p = argv; *p; p++) {
55 rpmluavSetValue(var, RPMLUAV_STRING, *p);
56 rpmluaSetVar(lua, var);
60 rpmluavSetValueNum(var, arg1);
61 rpmluaSetVar(lua, var);
64 rpmluavSetValueNum(var, arg2);
65 rpmluaSetVar(lua, var);
67 var = rpmluavFree(var);
70 if (rpmluaRunScript(lua, script, sname) == 0) {
74 rpmluaDelVar(lua, "arg");
77 const char *rootDir = rpmtsRootDir(ts);
80 if (rootDir != NULL && !rstreq(rootDir, "/") && *rootDir == '/')
82 xx = rpmtsSetChrootDone(ts, 0);
85 rpmlog(lvl, _("<lua> scriptlet support not built in\n"));
91 static const char * const SCRIPT_PATH = "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin";
93 static void doScriptExec(rpmts ts, ARGV_const_t argv, ARGV_const_t prefixes,
94 FD_t scriptFd, FD_t out)
103 (void) signal(SIGPIPE, SIG_DFL);
104 pipes[0] = pipes[1] = 0;
105 /* make stdin inaccessible */
107 xx = close(pipes[1]);
108 xx = dup2(pipes[0], STDIN_FILENO);
109 xx = close(pipes[0]);
111 /* XXX Force FD_CLOEXEC on all inherited fdno's. */
112 open_max = sysconf(_SC_OPEN_MAX);
113 if (open_max == -1) {
116 for (fdno = 3; fdno < open_max; fdno++) {
117 flag = fcntl(fdno, F_GETFD);
118 if (flag == -1 || (flag & FD_CLOEXEC))
120 xx = fcntl(fdno, F_SETFD, FD_CLOEXEC);
121 /* XXX W2DO? debug msg for inheirited fdno w/o FD_CLOEXEC */
124 if (scriptFd != NULL) {
125 int sfdno = Fileno(scriptFd);
126 int ofdno = Fileno(out);
127 if (sfdno != STDERR_FILENO)
128 xx = dup2(sfdno, STDERR_FILENO);
129 if (ofdno != STDOUT_FILENO)
130 xx = dup2(ofdno, STDOUT_FILENO);
131 /* make sure we don't close stdin/stderr/stdout by mistake! */
132 if (ofdno > STDERR_FILENO && ofdno != sfdno)
134 if (sfdno > STDERR_FILENO && ofdno != sfdno)
135 xx = Fclose (scriptFd);
138 { char *ipath = rpmExpand("%{_install_script_path}", NULL);
139 const char *path = SCRIPT_PATH;
141 if (ipath && ipath[5] != '%')
144 xx = setenv("PATH", path, 1);
145 ipath = _free(ipath);
148 for (ARGV_const_t pf = prefixes; pf && *pf; pf++) {
150 int num = (pf - prefixes);
152 rasprintf(&name, "RPM_INSTALL_PREFIX%d", num);
153 setenv(name, *pf, 1);
156 /* scripts might still be using the old style prefix */
158 setenv("RPM_INSTALL_PREFIX", *pf, 1);
162 rootDir = rpmtsRootDir(ts);
163 if (rootDir != NULL) { /* XXX can't happen */
164 if (!rpmtsChrootDone(ts) &&
165 !(rootDir[0] == '/' && rootDir[1] == '\0'))
167 xx = chroot(rootDir);
171 /* XXX Don't mtrace into children. */
172 unsetenv("MALLOC_CHECK_");
174 /* Permit libselinux to do the scriptlet exec. */
175 if (rpmtsSELinuxEnabled(ts) == 1) {
176 xx = rpm_execcon(0, argv[0], argv, environ);
180 xx = execv(argv[0], argv);
183 _exit(127); /* exit 127 for compatibility with bash(1) */
187 * Run an external script.
189 static rpmRC runExtScript(rpmts ts, ARGV_const_t prefixes,
190 const char *sname, rpmlogLvl lvl,
191 ARGV_t * argvp, const char *script, int arg1, int arg2)
197 rpmRC rc = RPMRC_FAIL;
200 memset(&sq, 0, sizeof(sq));
203 rpmlog(RPMLOG_DEBUG, "%s: scriptlet start\n", sname);
206 const char * rootDir = rpmtsRootDir(ts);
209 fd = rpmMkTempFile((!rpmtsChrootDone(ts) ? rootDir : "/"), &fn);
210 if (fd == NULL || Ferror(fd)) {
211 rpmlog(RPMLOG_ERR, _("Couldn't create temporary file for %s: %s\n"),
212 sname, strerror(errno));
217 (rstreq(*argvp[0], "/bin/sh") || rstreq(*argvp[0], "/bin/bash")))
219 static const char set_x[] = "set -x\n";
220 xx = Fwrite(set_x, sizeof(set_x[0]), sizeof(set_x)-1, fd);
223 xx = Fwrite(script, sizeof(script[0]), strlen(script), fd);
226 { const char * sn = fn;
227 if (!rpmtsChrootDone(ts) && rootDir != NULL &&
228 !(rootDir[0] == '/' && rootDir[1] == '\0'))
230 sn += strlen(rootDir)-1;
236 argvAddNum(argvp, arg1);
239 argvAddNum(argvp, arg2);
243 scriptFd = rpmtsScriptFd(ts);
244 if (scriptFd != NULL) {
245 if (rpmIsVerbose()) {
246 out = fdDup(Fileno(scriptFd));
248 out = Fopen("/dev/null", "w.fdio");
250 out = fdDup(Fileno(scriptFd));
254 out = fdDup(STDOUT_FILENO);
257 rpmlog(RPMLOG_ERR, _("Couldn't duplicate file descriptor: %s: %s\n"),
258 sname, strerror(errno));
264 rpmlog(RPMLOG_DEBUG, "%s: execv(%s) pid %d\n",
265 sname, *argvp[0], (unsigned)getpid());
266 doScriptExec(ts, *argvp, prefixes, scriptFd, out);
269 if (sq.child == (pid_t)-1) {
270 rpmlog(RPMLOG_ERR, _("Couldn't fork %s: %s\n"), sname, strerror(errno));
276 rpmlog(RPMLOG_DEBUG, "%s: waitpid(%d) rc %d status %x\n",
277 sname, (unsigned)sq.child, (unsigned)sq.reaped, sq.status);
280 rpmlog(lvl, _("%s scriptlet failed, waitpid(%d) rc %d: %s\n"),
281 sname, sq.child, sq.reaped, strerror(errno));
282 } else if (!WIFEXITED(sq.status) || WEXITSTATUS(sq.status)) {
283 if (WIFSIGNALED(sq.status)) {
284 rpmlog(lvl, _("%s scriptlet failed, signal %d\n"),
285 sname, WTERMSIG(sq.status));
287 rpmlog(lvl, _("%s scriptlet failed, exit status %d\n"),
288 sname, WEXITSTATUS(sq.status));
291 /* if we get this far we're clear */
297 xx = Fclose(out); /* XXX dup'd STDOUT_FILENO */
307 rpmRC rpmScriptRun(rpmScript script, int arg1, int arg2,
308 rpmts ts, ARGV_const_t prefixes, int warn_only)
311 rpmlogLvl lvl = warn_only ? RPMLOG_WARNING : RPMLOG_ERR;
314 if (script == NULL) return RPMRC_OK;
316 /* construct a new argv as we can't modify the one from header */
318 argvAppend(&args, script->args);
320 argvAdd(&args, "/bin/sh");
323 rpmswEnter(rpmtsOp(ts, RPMTS_OP_SCRIPTLETS), 0);
324 if (rstreq(args[0], "<lua>")) {
325 rc = runLuaScript(ts, prefixes, script->descr, lvl, &args, script->body, arg1, arg2);
327 rc = runExtScript(ts, prefixes, script->descr, lvl, &args, script->body, arg1, arg2);
329 rpmswExit(rpmtsOp(ts, RPMTS_OP_SCRIPTLETS), 0);
335 static rpmTag getProgTag(rpmTag scriptTag)
338 case RPMTAG_PREIN: return RPMTAG_PREINPROG;
339 case RPMTAG_POSTIN: return RPMTAG_POSTINPROG;
340 case RPMTAG_PREUN: return RPMTAG_PREUNPROG;
341 case RPMTAG_POSTUN: return RPMTAG_POSTUNPROG;
342 case RPMTAG_PRETRANS: return RPMTAG_PRETRANSPROG;
343 case RPMTAG_POSTTRANS: return RPMTAG_POSTTRANSPROG;
344 case RPMTAG_VERIFYSCRIPT: return RPMTAG_VERIFYSCRIPTPROG;
345 default: return RPMTAG_NOT_FOUND;
349 static const char * tag2sln(rpmTag tag)
351 switch ((rpm_tag_t) tag) {
352 case RPMTAG_PRETRANS: return "%pretrans";
353 case RPMTAG_TRIGGERPREIN: return "%triggerprein";
354 case RPMTAG_PREIN: return "%pre";
355 case RPMTAG_POSTIN: return "%post";
356 case RPMTAG_TRIGGERIN: return "%triggerin";
357 case RPMTAG_TRIGGERUN: return "%triggerun";
358 case RPMTAG_PREUN: return "%preun";
359 case RPMTAG_POSTUN: return "%postun";
360 case RPMTAG_POSTTRANS: return "%posttrans";
361 case RPMTAG_TRIGGERPOSTUN: return "%triggerpostun";
362 case RPMTAG_VERIFYSCRIPT: return "%verify";
365 return "%unknownscript";
368 rpmScript rpmScriptFromTag(Header h, rpmTag scriptTag)
370 rpmScript script = NULL;
371 rpmTag progTag = getProgTag(scriptTag);
373 if (headerIsEntry(h, scriptTag) || headerIsEntry(h, progTag)) {
375 char *nevra = headerGetAsString(h, RPMTAG_NEVRA);
377 script = xcalloc(1, sizeof(*script));
378 script->tag = scriptTag;
379 script->body = headerGetAsString(h, scriptTag);
380 rasprintf(&script->descr, "%s(%s)", tag2sln(scriptTag), nevra);
382 if (headerGet(h, progTag, &prog, (HEADERGET_ALLOC|HEADERGET_ARGV))) {
383 script->args = prog.data;
390 rpmScript rpmScriptFree(rpmScript script)