summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Makefile.am2
-rw-r--r--lib/psm.c417
-rw-r--r--lib/psm.h2
-rw-r--r--lib/rpmscript.c399
-rw-r--r--lib/rpmscript.h26
5 files changed, 457 insertions, 389 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
index af264a282..fb7e7bfeb 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -32,7 +32,7 @@ librpm_la_SOURCES = \
rpmte.c rpmte_internal.h rpmts.c \
rpmvercmp.c signature.c signature.h transaction.c \
verify.c rpmlock.c rpmlock.h misc.h \
- legacy.c merge.c \
+ rpmscript.h rpmscript.c legacy.c merge.c \
rpmliblua.c rpmliblua.h
librpm_la_LDFLAGS = -version-info 1:0:0
diff --git a/lib/psm.c b/lib/psm.c
index bc5676778..269407b60 100644
--- a/lib/psm.c
+++ b/lib/psm.c
@@ -9,16 +9,14 @@
#include <rpm/rpmlib.h> /* rpmvercmp and others */
#include <rpm/rpmmacro.h>
-#include <rpm/rpmurl.h>
#include <rpm/rpmds.h>
#include <rpm/rpmts.h>
-#include <rpm/rpmfileutil.h> /* rpmMkTemp() */
+#include <rpm/rpmfileutil.h>
#include <rpm/rpmdb.h> /* XXX for db_chrootDone */
#include <rpm/rpmlog.h>
#include <rpm/rpmstring.h>
#include <rpm/argv.h>
-#include "rpmio/rpmlua.h"
#include "lib/cpio.h"
#include "lib/fsm.h" /* XXX CPIO_FOO/FSM_FOO constants */
#include "lib/psm.h"
@@ -26,6 +24,7 @@
#include "lib/rpmte_internal.h" /* XXX internal apis */
#include "lib/rpmlead.h" /* writeLead proto */
#include "lib/signature.h" /* signature constants */
+#include "lib/rpmscript.h"
#include "debug.h"
@@ -350,32 +349,6 @@ exit:
return rpmrc;
}
-static const char * const SCRIPT_PATH = "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin";
-
-/**
- * Return scriptlet name from tag.
- * @param tag scriptlet tag
- * @return name of scriptlet
- */
-static const char * tag2sln(rpmTag tag)
-{
- switch ((rpm_tag_t) tag) {
- case RPMTAG_PRETRANS: return "%pretrans";
- case RPMTAG_TRIGGERPREIN: return "%triggerprein";
- case RPMTAG_PREIN: return "%pre";
- case RPMTAG_POSTIN: return "%post";
- case RPMTAG_TRIGGERIN: return "%triggerin";
- case RPMTAG_TRIGGERUN: return "%triggerun";
- case RPMTAG_PREUN: return "%preun";
- case RPMTAG_POSTUN: return "%postun";
- case RPMTAG_POSTTRANS: return "%posttrans";
- case RPMTAG_TRIGGERPOSTUN: return "%triggerpostun";
- case RPMTAG_VERIFYSCRIPT: return "%verify";
- default: break;
- }
- return "%unknownscript";
-}
-
static rpmTag triggertag(rpmsenseFlags sense)
{
rpmTag tag = RPMTAG_NOT_FOUND;
@@ -399,295 +372,7 @@ static rpmTag triggertag(rpmsenseFlags sense)
}
/**
- * Run internal Lua script.
- */
-static rpmRC runLuaScript(rpmts ts, ARGV_const_t prefixes,
- const char *sname, rpmlogLvl lvl,
- ARGV_t * argvp, const char *script, int arg1, int arg2)
-{
- rpmRC rc = RPMRC_FAIL;
-#ifdef WITH_LUA
- int rootFd = -1;
- int xx;
- ARGV_t argv = argvp ? *argvp : NULL;
- rpmlua lua = NULL; /* Global state. */
- rpmluav var;
-
- rpmlog(RPMLOG_DEBUG, "%s: running <lua> scriptlet.\n", sname);
- if (!rpmtsChrootDone(ts)) {
- const char *rootDir = rpmtsRootDir(ts);
- xx = chdir("/");
- rootFd = open(".", O_RDONLY, 0);
- if (rootFd >= 0) {
- if (rootDir != NULL && !rstreq(rootDir, "/") && *rootDir == '/')
- xx = chroot(rootDir);
- xx = rpmtsSetChrootDone(ts, 1);
- }
- }
-
- /* Create arg variable */
- rpmluaPushTable(lua, "arg");
- var = rpmluavNew();
- rpmluavSetListMode(var, 1);
- if (argv) {
- char **p;
- for (p = argv; *p; p++) {
- rpmluavSetValue(var, RPMLUAV_STRING, *p);
- rpmluaSetVar(lua, var);
- }
- }
- if (arg1 >= 0) {
- rpmluavSetValueNum(var, arg1);
- rpmluaSetVar(lua, var);
- }
- if (arg2 >= 0) {
- rpmluavSetValueNum(var, arg2);
- rpmluaSetVar(lua, var);
- }
- var = rpmluavFree(var);
- rpmluaPop(lua);
-
- if (rpmluaRunScript(lua, script, sname) == 0) {
- rc = RPMRC_OK;
- }
-
- rpmluaDelVar(lua, "arg");
-
- if (rootFd >= 0) {
- const char *rootDir = rpmtsRootDir(ts);
- xx = fchdir(rootFd);
- xx = close(rootFd);
- if (rootDir != NULL && !rstreq(rootDir, "/") && *rootDir == '/')
- xx = chroot(".");
- xx = rpmtsSetChrootDone(ts, 0);
- }
-#else
- rpmlog(lvl, _("<lua> scriptlet support not built in\n"));
-#endif
-
- return rc;
-}
-
-static void doScriptExec(rpmts ts, ARGV_const_t argv, ARGV_const_t prefixes,
- FD_t scriptFd, FD_t out)
-{
- const char * rootDir;
- int pipes[2];
- int flag;
- int fdno;
- int xx;
- int open_max;
-
- (void) signal(SIGPIPE, SIG_DFL);
- pipes[0] = pipes[1] = 0;
- /* make stdin inaccessible */
- xx = pipe(pipes);
- xx = close(pipes[1]);
- xx = dup2(pipes[0], STDIN_FILENO);
- xx = close(pipes[0]);
-
- /* XXX Force FD_CLOEXEC on all inherited fdno's. */
- open_max = sysconf(_SC_OPEN_MAX);
- if (open_max == -1) {
- open_max = 1024;
- }
- for (fdno = 3; fdno < open_max; fdno++) {
- flag = fcntl(fdno, F_GETFD);
- if (flag == -1 || (flag & FD_CLOEXEC))
- continue;
- xx = fcntl(fdno, F_SETFD, FD_CLOEXEC);
- /* XXX W2DO? debug msg for inheirited fdno w/o FD_CLOEXEC */
- }
-
- if (scriptFd != NULL) {
- int sfdno = Fileno(scriptFd);
- int ofdno = Fileno(out);
- if (sfdno != STDERR_FILENO)
- xx = dup2(sfdno, STDERR_FILENO);
- if (ofdno != STDOUT_FILENO)
- xx = dup2(ofdno, STDOUT_FILENO);
- /* make sure we don't close stdin/stderr/stdout by mistake! */
- if (ofdno > STDERR_FILENO && ofdno != sfdno)
- xx = Fclose (out);
- if (sfdno > STDERR_FILENO && ofdno != sfdno)
- xx = Fclose (scriptFd);
- }
-
- { char *ipath = rpmExpand("%{_install_script_path}", NULL);
- const char *path = SCRIPT_PATH;
-
- if (ipath && ipath[5] != '%')
- path = ipath;
-
- xx = setenv("PATH", path, 1);
- ipath = _free(ipath);
- }
-
- for (ARGV_const_t pf = prefixes; pf && *pf; pf++) {
- char *name = NULL;
- int num = (pf - prefixes);
-
- rasprintf(&name, "RPM_INSTALL_PREFIX%d", num);
- setenv(name, *pf, 1);
- free(name);
-
- /* scripts might still be using the old style prefix */
- if (num == 0) {
- setenv("RPM_INSTALL_PREFIX", *pf, 1);
- }
- }
-
- rootDir = rpmtsRootDir(ts);
- if (rootDir != NULL) { /* XXX can't happen */
- if (!rpmtsChrootDone(ts) &&
- !(rootDir[0] == '/' && rootDir[1] == '\0'))
- {
- xx = chroot(rootDir);
- }
- xx = chdir("/");
-
- /* XXX Don't mtrace into children. */
- unsetenv("MALLOC_CHECK_");
-
- /* Permit libselinux to do the scriptlet exec. */
- if (rpmtsSELinuxEnabled(ts) == 1) {
- xx = rpm_execcon(0, argv[0], argv, environ);
- }
-
- if (xx == 0) {
- xx = execv(argv[0], argv);
- }
- }
- _exit(127); /* exit 127 for compatibility with bash(1) */
-}
-
-/**
- * Run an external script.
- */
-static rpmRC runExtScript(rpmts ts, ARGV_const_t prefixes,
- const char *sname, rpmlogLvl lvl,
- ARGV_t * argvp, const char *script, int arg1, int arg2)
-{
- FD_t scriptFd;
- FD_t out = NULL;
- char * fn = NULL;
- int xx;
- rpmRC rc = RPMRC_FAIL;
- struct rpmsqElem sq;
-
- memset(&sq, 0, sizeof(sq));
- sq.reaper = 1;
-
- rpmlog(RPMLOG_DEBUG, "%s: scriptlet start\n", sname);
-
- if (argvCount(*argvp) == 0) {
- argvAdd(argvp, "/bin/sh");
- }
-
- if (script) {
- const char * rootDir = rpmtsRootDir(ts);
- FD_t fd;
-
- fd = rpmMkTempFile((!rpmtsChrootDone(ts) ? rootDir : "/"), &fn);
- if (fd == NULL || Ferror(fd)) {
- rpmlog(RPMLOG_ERR, _("Couldn't create temporary file for %s: %s\n"),
- sname, strerror(errno));
- goto exit;
- }
-
- if (rpmIsDebug() &&
- (rstreq(*argvp[0], "/bin/sh") || rstreq(*argvp[0], "/bin/bash")))
- {
- static const char set_x[] = "set -x\n";
- xx = Fwrite(set_x, sizeof(set_x[0]), sizeof(set_x)-1, fd);
- }
-
- xx = Fwrite(script, sizeof(script[0]), strlen(script), fd);
- xx = Fclose(fd);
-
- { const char * sn = fn;
- if (!rpmtsChrootDone(ts) && rootDir != NULL &&
- !(rootDir[0] == '/' && rootDir[1] == '\0'))
- {
- sn += strlen(rootDir)-1;
- }
- argvAdd(argvp, sn);
- }
-
- if (arg1 >= 0) {
- argvAddNum(argvp, arg1);
- }
- if (arg2 >= 0) {
- argvAddNum(argvp, arg2);
- }
- }
-
- scriptFd = rpmtsScriptFd(ts);
- if (scriptFd != NULL) {
- if (rpmIsVerbose()) {
- out = fdDup(Fileno(scriptFd));
- } else {
- out = Fopen("/dev/null", "w.fdio");
- if (Ferror(out)) {
- out = fdDup(Fileno(scriptFd));
- }
- }
- } else {
- out = fdDup(STDOUT_FILENO);
- }
- if (out == NULL) {
- rpmlog(RPMLOG_ERR, _("Couldn't duplicate file descriptor: %s: %s\n"),
- sname, strerror(errno));
- goto exit;
- }
-
- xx = rpmsqFork(&sq);
- if (sq.child == 0) {
- rpmlog(RPMLOG_DEBUG, "%s: execv(%s) pid %d\n",
- sname, *argvp[0], (unsigned)getpid());
- doScriptExec(ts, *argvp, prefixes, scriptFd, out);
- }
-
- if (sq.child == (pid_t)-1) {
- rpmlog(RPMLOG_ERR, _("Couldn't fork %s: %s\n"), sname, strerror(errno));
- goto exit;
- }
-
- rpmsqWait(&sq);
-
- rpmlog(RPMLOG_DEBUG, "%s: waitpid(%d) rc %d status %x\n",
- sname, (unsigned)sq.child, (unsigned)sq.reaped, sq.status);
-
- if (sq.reaped < 0) {
- rpmlog(lvl, _("%s scriptlet failed, waitpid(%d) rc %d: %s\n"),
- sname, sq.child, sq.reaped, strerror(errno));
- } else if (!WIFEXITED(sq.status) || WEXITSTATUS(sq.status)) {
- if (WIFSIGNALED(sq.status)) {
- rpmlog(lvl, _("%s scriptlet failed, signal %d\n"),
- sname, WTERMSIG(sq.status));
- } else {
- rpmlog(lvl, _("%s scriptlet failed, exit status %d\n"),
- sname, WEXITSTATUS(sq.status));
- }
- } else {
- /* if we get this far we're clear */
- rc = RPMRC_OK;
- }
-
-exit:
- if (out)
- xx = Fclose(out); /* XXX dup'd STDOUT_FILENO */
-
- if (script) {
- if (!rpmIsDebug())
- xx = unlink(fn);
- fn = _free(fn);
- }
- return rc;
-}
-
-/**
- * Run scriptlet with args.
+ * Run a scriptlet with args.
*
* Run a script with an interpreter. If the interpreter is not specified,
* /bin/sh will be used. If the interpreter is /bin/sh, then the args from
@@ -695,89 +380,50 @@ exit:
*
* @param psm package state machine data
* @param prefixes install prefixes
- * @param stag scriptlet section tag
- * @param argvp ARGV_t pointer to args from header, *argvp[0] is the
- * interpreter to use. Pointer as we might need to
- * modify via argvAdd()
* @param script scriptlet from header
* @param arg1 no. instances of package installed after scriptlet exec
* (-1 is no arg)
* @param arg2 ditto, but for the target package
* @return 0 on success
*/
-static rpmRC runScript(rpmpsm psm, ARGV_const_t prefixes, rpmTag stag,
- ARGV_t * argvp, const char * script, int arg1, int arg2)
+static rpmRC runScript(rpmpsm psm, ARGV_const_t prefixes,
+ rpmScript script, int arg1, int arg2)
{
- rpmRC rc = RPMRC_FAIL; /* assume failure */
- char *sname = NULL;
- int warn_only = (stag != RPMTAG_PREIN && stag != RPMTAG_PREUN);
- rpmlogLvl loglvl = warn_only ? RPMLOG_WARNING : RPMLOG_ERR;
-
- if (*argvp == NULL && script == NULL)
- return RPMRC_OK;
-
- rasprintf(&sname, "%s(%s)", tag2sln(stag), rpmteNEVRA(psm->te));
-
- rpmswEnter(rpmtsOp(psm->ts, RPMTS_OP_SCRIPTLETS), 0);
- if (*argvp[0] && rstreq(*argvp[0], "<lua>")) {
- rc = runLuaScript(psm->ts, prefixes, sname, loglvl, argvp, script, arg1, arg2);
- } else {
- rc = runExtScript(psm->ts, prefixes, sname, loglvl, argvp, script, arg1, arg2);
- }
- rpmswExit(rpmtsOp(psm->ts, RPMTS_OP_SCRIPTLETS), 0);
+ rpmRC rc = RPMRC_OK;
+ int warn_only =(script->tag != RPMTAG_PREIN && script->tag != RPMTAG_PREUN);
/*
* Notify callback for all errors. "total" abused for warning/error,
* rc only reflects whether the condition prevented install/erase
* (which is only happens with %prein and %preun scriptlets) or not.
*/
+ rc = rpmScriptRun(script, arg1, arg2, psm->ts, prefixes, warn_only);
if (rc != RPMRC_OK) {
if (warn_only) {
rc = RPMRC_OK;
}
- rpmtsNotify(psm->ts, psm->te, RPMCALLBACK_SCRIPT_ERROR, stag, rc);
+ rpmtsNotify(psm->ts, psm->te, RPMCALLBACK_SCRIPT_ERROR, script->tag, rc);
}
- free(sname);
return rc;
}
-/**
- * Retrieve and run scriptlet from header.
- * @param psm package state machine data
- * @return rpmRC return code
- */
static rpmRC runInstScript(rpmpsm psm)
{
rpmRC rc = RPMRC_OK;
- ARGV_t argv;
- struct rpmtd_s script, prog, pfx;
- const char *str;
+ struct rpmtd_s pfx;
Header h = rpmteHeader(psm->te);
+ rpmScript script = rpmScriptFromTag(h, psm->scriptTag);
- if (h == NULL) /* XXX can't happen */
- return RPMRC_FAIL;
-
- headerGet(h, psm->scriptTag, &script, HEADERGET_DEFAULT);
- headerGet(h, psm->progTag, &prog, HEADERGET_DEFAULT);
- if (rpmtdCount(&script) == 0 && rpmtdCount(&prog) == 0)
- goto exit;
-
- argv = argvNew();
- while ((str = rpmtdNextString(&prog))) {
- argvAdd(&argv, str);
+ if (script) {
+ headerGet(h, RPMTAG_INSTPREFIXES, &pfx, HEADERGET_ALLOC|HEADERGET_ARGV);
+ rc = runScript(psm, pfx.data, script, psm->scriptArg, -1);
+ rpmtdFreeData(&pfx);
}
- headerGet(h, RPMTAG_INSTPREFIXES, &pfx, HEADERGET_ALLOC|HEADERGET_ARGV);
- rc = runScript(psm, pfx.data, psm->scriptTag, &argv,
- rpmtdGetString(&script), psm->scriptArg, -1);
- rpmtdFreeData(&pfx);
- argvFree(argv);
-
-exit:
- rpmtdFreeData(&script);
- rpmtdFreeData(&prog);
+ rpmScriptFree(script);
headerFree(h);
+
return rc;
}
@@ -830,24 +476,29 @@ static rpmRC handleOneTrigger(const rpmpsm psm,
continue;
} else {
int arg1 = rpmdbCountPackages(rpmtsGetRdb(ts), triggerName);
- const char ** triggerScripts = tscripts.data;
- const char ** triggerProgs = tprogs.data;
+ char ** triggerScripts = tscripts.data;
+ char ** triggerProgs = tprogs.data;
uint32_t * triggerIndices = tindexes.data;
+ uint32_t ix = triggerIndices[i];
if (arg1 < 0) {
/* XXX W2DO? fails as "execution of script failed" */
rc = RPMRC_FAIL;
} else {
arg1 += psm->countCorrection;
- int ix = triggerIndices[i];
+
if (triggersAlreadyRun == NULL || triggersAlreadyRun[ix] == 0) {
- ARGV_t argv = argvNew();
- argvAdd(&argv, *(triggerProgs + ix));
- rc = runScript(psm, pfx.data, triggertag(psm->sense),
- &argv, triggerScripts[ix], arg1, arg2);
+ /* construct script manually, this must not be freed */
+ char *args[2] = { triggerProgs[ix], NULL };
+ struct rpmScript_s script = {
+ .tag = triggertag(psm->sense),
+ .body = triggerScripts[ix],
+ .args = args
+ };
+
+ rc = runScript(psm, pfx.data, &script, arg1, arg2);
if (triggersAlreadyRun != NULL)
triggersAlreadyRun[ix] = 1;
- argvFree(argv);
}
}
}
@@ -1179,13 +830,7 @@ rpmRC rpmpsmStage(rpmpsm psm, pkgStage stage)
if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPRE)) {
rc = rpmpsmNext(psm, PSM_SCRIPT);
- if (rc != RPMRC_OK) {
- rpmlog(RPMLOG_ERR,
- _("%s: %s scriptlet failed (%d), skipping %s\n"),
- psm->stepName, tag2sln(psm->scriptTag), rc,
- rpmteNEVR(psm->te));
- break;
- }
+ if (rc) break;
}
}
diff --git a/lib/psm.h b/lib/psm.h
index 7d2a3091c..9a61ecf23 100644
--- a/lib/psm.h
+++ b/lib/psm.h
@@ -6,8 +6,6 @@
* Package state machine to handle a package from a transaction set.
*/
-#define _RPMSQ_INTERNAL
-#include <rpm/rpmsq.h>
#include <rpm/rpmcallback.h>
extern int _psm_debug;
diff --git a/lib/rpmscript.c b/lib/rpmscript.c
new file mode 100644
index 000000000..4cde9bb84
--- /dev/null
+++ b/lib/rpmscript.c
@@ -0,0 +1,399 @@
+#include "system.h"
+
+#include <errno.h>
+#include <unistd.h>
+
+#define _RPMSQ_INTERNAL
+#include <rpm/rpmsq.h>
+#include <rpm/rpmts.h>
+#include <rpm/rpmfileutil.h>
+#include <rpm/rpmmacro.h>
+#include <rpm/rpmio.h>
+#include <rpm/rpmlog.h>
+#include <rpm/rpmsw.h>
+#include <rpm/header.h>
+
+#include "rpmio/rpmlua.h"
+#include "lib/rpmscript.h"
+
+#include "debug.h"
+
+/**
+ * Run internal Lua script.
+ */
+static rpmRC runLuaScript(rpmts ts, ARGV_const_t prefixes,
+ const char *sname, rpmlogLvl lvl,
+ ARGV_t * argvp, const char *script, int arg1, int arg2)
+{
+ rpmRC rc = RPMRC_FAIL;
+#ifdef WITH_LUA
+ int rootFd = -1;
+ int xx;
+ ARGV_t argv = argvp ? *argvp : NULL;
+ rpmlua lua = NULL; /* Global state. */
+ rpmluav var;
+
+ rpmlog(RPMLOG_DEBUG, "%s: running <lua> scriptlet.\n", sname);
+ if (!rpmtsChrootDone(ts)) {
+ const char *rootDir = rpmtsRootDir(ts);
+ xx = chdir("/");
+ rootFd = open(".", O_RDONLY, 0);
+ if (rootFd >= 0) {
+ if (rootDir != NULL && !rstreq(rootDir, "/") && *rootDir == '/')
+ xx = chroot(rootDir);
+ xx = rpmtsSetChrootDone(ts, 1);
+ }
+ }
+
+ /* Create arg variable */
+ rpmluaPushTable(lua, "arg");
+ var = rpmluavNew();
+ rpmluavSetListMode(var, 1);
+ if (argv) {
+ char **p;
+ for (p = argv; *p; p++) {
+ rpmluavSetValue(var, RPMLUAV_STRING, *p);
+ rpmluaSetVar(lua, var);
+ }
+ }
+ if (arg1 >= 0) {
+ rpmluavSetValueNum(var, arg1);
+ rpmluaSetVar(lua, var);
+ }
+ if (arg2 >= 0) {
+ rpmluavSetValueNum(var, arg2);
+ rpmluaSetVar(lua, var);
+ }
+ var = rpmluavFree(var);
+ rpmluaPop(lua);
+
+ if (rpmluaRunScript(lua, script, sname) == 0) {
+ rc = RPMRC_OK;
+ }
+
+ rpmluaDelVar(lua, "arg");
+
+ if (rootFd >= 0) {
+ const char *rootDir = rpmtsRootDir(ts);
+ xx = fchdir(rootFd);
+ xx = close(rootFd);
+ if (rootDir != NULL && !rstreq(rootDir, "/") && *rootDir == '/')
+ xx = chroot(".");
+ xx = rpmtsSetChrootDone(ts, 0);
+ }
+#else
+ rpmlog(lvl, _("<lua> scriptlet support not built in\n"));
+#endif
+
+ return rc;
+}
+
+static const char * const SCRIPT_PATH = "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin";
+
+static void doScriptExec(rpmts ts, ARGV_const_t argv, ARGV_const_t prefixes,
+ FD_t scriptFd, FD_t out)
+{
+ const char * rootDir;
+ int pipes[2];
+ int flag;
+ int fdno;
+ int xx;
+ int open_max;
+
+ (void) signal(SIGPIPE, SIG_DFL);
+ pipes[0] = pipes[1] = 0;
+ /* make stdin inaccessible */
+ xx = pipe(pipes);
+ xx = close(pipes[1]);
+ xx = dup2(pipes[0], STDIN_FILENO);
+ xx = close(pipes[0]);
+
+ /* XXX Force FD_CLOEXEC on all inherited fdno's. */
+ open_max = sysconf(_SC_OPEN_MAX);
+ if (open_max == -1) {
+ open_max = 1024;
+ }
+ for (fdno = 3; fdno < open_max; fdno++) {
+ flag = fcntl(fdno, F_GETFD);
+ if (flag == -1 || (flag & FD_CLOEXEC))
+ continue;
+ xx = fcntl(fdno, F_SETFD, FD_CLOEXEC);
+ /* XXX W2DO? debug msg for inheirited fdno w/o FD_CLOEXEC */
+ }
+
+ if (scriptFd != NULL) {
+ int sfdno = Fileno(scriptFd);
+ int ofdno = Fileno(out);
+ if (sfdno != STDERR_FILENO)
+ xx = dup2(sfdno, STDERR_FILENO);
+ if (ofdno != STDOUT_FILENO)
+ xx = dup2(ofdno, STDOUT_FILENO);
+ /* make sure we don't close stdin/stderr/stdout by mistake! */
+ if (ofdno > STDERR_FILENO && ofdno != sfdno)
+ xx = Fclose (out);
+ if (sfdno > STDERR_FILENO && ofdno != sfdno)
+ xx = Fclose (scriptFd);
+ }
+
+ { char *ipath = rpmExpand("%{_install_script_path}", NULL);
+ const char *path = SCRIPT_PATH;
+
+ if (ipath && ipath[5] != '%')
+ path = ipath;
+
+ xx = setenv("PATH", path, 1);
+ ipath = _free(ipath);
+ }
+
+ for (ARGV_const_t pf = prefixes; pf && *pf; pf++) {
+ char *name = NULL;
+ int num = (pf - prefixes);
+
+ rasprintf(&name, "RPM_INSTALL_PREFIX%d", num);
+ setenv(name, *pf, 1);
+ free(name);
+
+ /* scripts might still be using the old style prefix */
+ if (num == 0) {
+ setenv("RPM_INSTALL_PREFIX", *pf, 1);
+ }
+ }
+
+ rootDir = rpmtsRootDir(ts);
+ if (rootDir != NULL) { /* XXX can't happen */
+ if (!rpmtsChrootDone(ts) &&
+ !(rootDir[0] == '/' && rootDir[1] == '\0'))
+ {
+ xx = chroot(rootDir);
+ }
+ xx = chdir("/");
+
+ /* XXX Don't mtrace into children. */
+ unsetenv("MALLOC_CHECK_");
+
+ /* Permit libselinux to do the scriptlet exec. */
+ if (rpmtsSELinuxEnabled(ts) == 1) {
+ xx = rpm_execcon(0, argv[0], argv, environ);
+ }
+
+ if (xx == 0) {
+ xx = execv(argv[0], argv);
+ }
+ }
+ _exit(127); /* exit 127 for compatibility with bash(1) */
+}
+
+/**
+ * Run an external script.
+ */
+static rpmRC runExtScript(rpmts ts, ARGV_const_t prefixes,
+ const char *sname, rpmlogLvl lvl,
+ ARGV_t * argvp, const char *script, int arg1, int arg2)
+{
+ FD_t scriptFd;
+ FD_t out = NULL;
+ char * fn = NULL;
+ int xx;
+ rpmRC rc = RPMRC_FAIL;
+ struct rpmsqElem sq;
+
+ memset(&sq, 0, sizeof(sq));
+ sq.reaper = 1;
+
+ rpmlog(RPMLOG_DEBUG, "%s: scriptlet start\n", sname);
+
+ if (script) {
+ const char * rootDir = rpmtsRootDir(ts);
+ FD_t fd;
+
+ fd = rpmMkTempFile((!rpmtsChrootDone(ts) ? rootDir : "/"), &fn);
+ if (fd == NULL || Ferror(fd)) {
+ rpmlog(RPMLOG_ERR, _("Couldn't create temporary file for %s: %s\n"),
+ sname, strerror(errno));
+ goto exit;
+ }
+
+ if (rpmIsDebug() &&
+ (rstreq(*argvp[0], "/bin/sh") || rstreq(*argvp[0], "/bin/bash")))
+ {
+ static const char set_x[] = "set -x\n";
+ xx = Fwrite(set_x, sizeof(set_x[0]), sizeof(set_x)-1, fd);
+ }
+
+ xx = Fwrite(script, sizeof(script[0]), strlen(script), fd);
+ xx = Fclose(fd);
+
+ { const char * sn = fn;
+ if (!rpmtsChrootDone(ts) && rootDir != NULL &&
+ !(rootDir[0] == '/' && rootDir[1] == '\0'))
+ {
+ sn += strlen(rootDir)-1;
+ }
+ argvAdd(argvp, sn);
+ }
+
+ if (arg1 >= 0) {
+ argvAddNum(argvp, arg1);
+ }
+ if (arg2 >= 0) {
+ argvAddNum(argvp, arg2);
+ }
+ }
+
+ scriptFd = rpmtsScriptFd(ts);
+ if (scriptFd != NULL) {
+ if (rpmIsVerbose()) {
+ out = fdDup(Fileno(scriptFd));
+ } else {
+ out = Fopen("/dev/null", "w.fdio");
+ if (Ferror(out)) {
+ out = fdDup(Fileno(scriptFd));
+ }
+ }
+ } else {
+ out = fdDup(STDOUT_FILENO);
+ }
+ if (out == NULL) {
+ rpmlog(RPMLOG_ERR, _("Couldn't duplicate file descriptor: %s: %s\n"),
+ sname, strerror(errno));
+ goto exit;
+ }
+
+ xx = rpmsqFork(&sq);
+ if (sq.child == 0) {
+ rpmlog(RPMLOG_DEBUG, "%s: execv(%s) pid %d\n",
+ sname, *argvp[0], (unsigned)getpid());
+ doScriptExec(ts, *argvp, prefixes, scriptFd, out);
+ }
+
+ if (sq.child == (pid_t)-1) {
+ rpmlog(RPMLOG_ERR, _("Couldn't fork %s: %s\n"), sname, strerror(errno));
+ goto exit;
+ }
+
+ rpmsqWait(&sq);
+
+ rpmlog(RPMLOG_DEBUG, "%s: waitpid(%d) rc %d status %x\n",
+ sname, (unsigned)sq.child, (unsigned)sq.reaped, sq.status);
+
+ if (sq.reaped < 0) {
+ rpmlog(lvl, _("%s scriptlet failed, waitpid(%d) rc %d: %s\n"),
+ sname, sq.child, sq.reaped, strerror(errno));
+ } else if (!WIFEXITED(sq.status) || WEXITSTATUS(sq.status)) {
+ if (WIFSIGNALED(sq.status)) {
+ rpmlog(lvl, _("%s scriptlet failed, signal %d\n"),
+ sname, WTERMSIG(sq.status));
+ } else {
+ rpmlog(lvl, _("%s scriptlet failed, exit status %d\n"),
+ sname, WEXITSTATUS(sq.status));
+ }
+ } else {
+ /* if we get this far we're clear */
+ rc = RPMRC_OK;
+ }
+
+exit:
+ if (out)
+ xx = Fclose(out); /* XXX dup'd STDOUT_FILENO */
+
+ if (script) {
+ if (!rpmIsDebug())
+ xx = unlink(fn);
+ fn = _free(fn);
+ }
+ return rc;
+}
+
+rpmRC rpmScriptRun(rpmScript script, int arg1, int arg2,
+ rpmts ts, ARGV_const_t prefixes, int warn_only)
+{
+ ARGV_t args = NULL;
+ rpmlogLvl lvl = warn_only ? RPMLOG_WARNING : RPMLOG_ERR;
+ rpmRC rc;
+
+ if (script == NULL) return RPMRC_OK;
+
+ /* construct a new argv as we can't modify the one from header */
+ if (script->args) {
+ argvAppend(&args, script->args);
+ } else {
+ argvAdd(&args, "/bin/sh");
+ }
+
+ rpmswEnter(rpmtsOp(ts, RPMTS_OP_SCRIPTLETS), 0);
+ if (rstreq(args[0], "<lua>")) {
+ rc = runLuaScript(ts, prefixes, script->descr, lvl, &args, script->body, arg1, arg2);
+ } else {
+ rc = runExtScript(ts, prefixes, script->descr, lvl, &args, script->body, arg1, arg2);
+ }
+ rpmswExit(rpmtsOp(ts, RPMTS_OP_SCRIPTLETS), 0);
+ argvFree(args);
+
+ return rc;
+}
+
+static rpmTag getProgTag(rpmTag scriptTag)
+{
+ switch (scriptTag) {
+ case RPMTAG_PREIN: return RPMTAG_PREINPROG;
+ case RPMTAG_POSTIN: return RPMTAG_POSTINPROG;
+ case RPMTAG_PREUN: return RPMTAG_PREUNPROG;
+ case RPMTAG_POSTUN: return RPMTAG_POSTUNPROG;
+ case RPMTAG_PRETRANS: return RPMTAG_PRETRANSPROG;
+ case RPMTAG_POSTTRANS: return RPMTAG_POSTTRANSPROG;
+ case RPMTAG_VERIFYSCRIPT: return RPMTAG_VERIFYSCRIPTPROG;
+ default: return RPMTAG_NOT_FOUND;
+ }
+}
+
+static const char * tag2sln(rpmTag tag)
+{
+ switch ((rpm_tag_t) tag) {
+ case RPMTAG_PRETRANS: return "%pretrans";
+ case RPMTAG_TRIGGERPREIN: return "%triggerprein";
+ case RPMTAG_PREIN: return "%pre";
+ case RPMTAG_POSTIN: return "%post";
+ case RPMTAG_TRIGGERIN: return "%triggerin";
+ case RPMTAG_TRIGGERUN: return "%triggerun";
+ case RPMTAG_PREUN: return "%preun";
+ case RPMTAG_POSTUN: return "%postun";
+ case RPMTAG_POSTTRANS: return "%posttrans";
+ case RPMTAG_TRIGGERPOSTUN: return "%triggerpostun";
+ case RPMTAG_VERIFYSCRIPT: return "%verify";
+ default: break;
+ }
+ return "%unknownscript";
+}
+
+rpmScript rpmScriptFromTag(Header h, rpmTag scriptTag)
+{
+ rpmScript script = NULL;
+ rpmTag progTag = getProgTag(scriptTag);
+
+ if (headerIsEntry(h, scriptTag) || headerIsEntry(h, progTag)) {
+ struct rpmtd_s prog;
+ char *nevra = headerGetAsString(h, RPMTAG_NEVRA);
+
+ script = xcalloc(1, sizeof(*script));
+ script->tag = scriptTag;
+ script->body = headerGetAsString(h, scriptTag);
+ rasprintf(&script->descr, "%s(%s)", tag2sln(scriptTag), nevra);
+
+ if (headerGet(h, progTag, &prog, (HEADERGET_ALLOC|HEADERGET_ARGV))) {
+ script->args = prog.data;
+ }
+ free(nevra);
+ }
+ return script;
+}
+
+rpmScript rpmScriptFree(rpmScript script)
+{
+ if (script) {
+ free(script->args);
+ free(script->body);
+ free(script->descr);
+ free(script);
+ }
+ return NULL;
+}
diff --git a/lib/rpmscript.h b/lib/rpmscript.h
new file mode 100644
index 000000000..8df2cc362
--- /dev/null
+++ b/lib/rpmscript.h
@@ -0,0 +1,26 @@
+#ifndef _RPMSCRIPT_H
+#define _RPMSCRIPT_H
+
+#include <rpm/rpmtypes.h>
+#include <rpm/argv.h>
+
+typedef struct rpmScript_s * rpmScript;
+
+struct rpmScript_s {
+ rpmTag tag; /* script tag */
+ char **args; /* scriptlet call arguments */
+ char *body; /* script body */
+ char *descr; /* description for logging */
+};
+
+RPM_GNUC_INTERNAL
+rpmScript rpmScriptFromTag(Header h, rpmTag scriptTag);
+
+RPM_GNUC_INTERNAL
+rpmScript rpmScriptFree(rpmScript script);
+
+RPM_GNUC_INTERNAL
+rpmRC rpmScriptRun(rpmScript script, int arg1, int arg2,
+ rpmts ts, ARGV_const_t prefixes, int warn_only);
+
+#endif /* _RPMSCRIPT_H */