summaryrefslogtreecommitdiff
path: root/lib/rpmscript.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rpmscript.c')
-rw-r--r--lib/rpmscript.c284
1 files changed, 220 insertions, 64 deletions
diff --git a/lib/rpmscript.c b/lib/rpmscript.c
index a27251c9a..cc98c4885 100644
--- a/lib/rpmscript.c
+++ b/lib/rpmscript.c
@@ -10,6 +10,7 @@
#include <rpm/rpmio.h>
#include <rpm/rpmlog.h>
#include <rpm/header.h>
+#include <rpm/rpmds.h>
#include "rpmio/rpmlua.h"
#include "lib/rpmscript.h"
@@ -18,20 +19,73 @@
#include "debug.h"
+struct scriptNextFileFunc_s {
+ char *(*func)(void *); /* function producing input for script */
+ void *param; /* parameter for func */
+};
+
+typedef struct scriptNextFileFunc_s *scriptNextFileFunc;
+
struct rpmScript_s {
+ rpmscriptTypes type; /* script type */
rpmTagVal tag; /* script tag */
char **args; /* scriptlet call arguments */
char *body; /* script body */
char *descr; /* description for logging */
rpmscriptFlags flags; /* flags to control operation */
+ struct scriptNextFileFunc_s nextFileFunc; /* input function */
+};
+
+struct scriptInfo_s {
+ rpmscriptTypes type;
+ const char *desc;
+ rpmsenseFlags sense;
+ rpmTagVal tag;
+ rpmTagVal progtag;
+ rpmTagVal flagtag;
+};
+
+static const struct scriptInfo_s scriptInfo[] = {
+ { RPMSCRIPT_PREIN, "%prein", 0,
+ RPMTAG_PREIN, RPMTAG_PREINPROG, RPMTAG_PREINFLAGS },
+ { RPMSCRIPT_PREUN, "%preun", 0,
+ RPMTAG_PREUN, RPMTAG_PREUNPROG, RPMTAG_PREUNFLAGS },
+ { RPMSCRIPT_POSTIN, "%post", 0,
+ RPMTAG_POSTIN, RPMTAG_POSTINPROG, RPMTAG_POSTINFLAGS },
+ { RPMSCRIPT_POSTUN, "%postun", 0,
+ RPMTAG_POSTUN, RPMTAG_POSTUNPROG, RPMTAG_POSTUNFLAGS },
+ { RPMSCRIPT_PRETRANS, "%pretrans", 0,
+ RPMTAG_PRETRANS, RPMTAG_PRETRANSPROG, RPMTAG_PRETRANSFLAGS },
+ { RPMSCRIPT_POSTTRANS, "%posttrans", 0,
+ RPMTAG_POSTTRANS, RPMTAG_POSTTRANSPROG, RPMTAG_POSTTRANSFLAGS },
+ { RPMSCRIPT_TRIGGERPREIN, "%triggerprein", RPMSENSE_TRIGGERPREIN,
+ RPMTAG_TRIGGERPREIN, 0, 0 },
+ { RPMSCRIPT_TRIGGERUN, "%triggerun", RPMSENSE_TRIGGERUN,
+ RPMTAG_TRIGGERUN, 0, 0 },
+ { RPMSCRIPT_TRIGGERIN, "%triggerin", RPMSENSE_TRIGGERIN,
+ RPMTAG_TRIGGERIN, 0, 0 },
+ { RPMSCRIPT_TRIGGERPOSTUN, "%triggerpostun", RPMSENSE_TRIGGERPOSTUN,
+ RPMTAG_TRIGGERPOSTUN, 0, 0 },
+ { RPMSCRIPT_VERIFY, "%verify", 0,
+ RPMTAG_VERIFYSCRIPT, RPMTAG_VERIFYSCRIPTPROG, RPMTAG_VERIFYSCRIPTFLAGS},
+ { 0, "unknown", 0,
+ RPMTAG_NOT_FOUND, RPMTAG_NOT_FOUND, RPMTAG_NOT_FOUND }
};
+static const struct scriptInfo_s * findTag(rpmTagVal tag)
+{
+ const struct scriptInfo_s * si = scriptInfo;
+ while (si->type && si->tag != tag)
+ si++;
+ return si;
+}
/**
* Run internal Lua script.
*/
-static rpmRC runLuaScript(rpmPlugins plugins, int selinux, ARGV_const_t prefixes,
+static rpmRC runLuaScript(rpmPlugins plugins, ARGV_const_t prefixes,
const char *sname, rpmlogLvl lvl, FD_t scriptFd,
- ARGV_t * argvp, const char *script, int arg1, int arg2)
+ ARGV_t * argvp, const char *script, int arg1, int arg2,
+ scriptNextFileFunc nextFileFunc)
{
rpmRC rc = RPMRC_FAIL;
#ifdef WITH_LUA
@@ -45,6 +99,7 @@ static rpmRC runLuaScript(rpmPlugins plugins, int selinux, ARGV_const_t prefixes
/* Create arg variable */
rpmluaPushTable(lua, "arg");
rpmluavSetListMode(var, 1);
+ rpmluaSetNextFileFunc(nextFileFunc->func, nextFileFunc->param);
if (argv) {
char **p;
for (p = argv; *p; p++) {
@@ -68,10 +123,16 @@ static rpmRC runLuaScript(rpmPlugins plugins, int selinux, ARGV_const_t prefixes
if (cwd != -1) {
mode_t oldmask = umask(0);
umask(oldmask);
+ pid_t pid = getpid();
if (chdir("/") == 0 && rpmluaRunScript(lua, script, sname) == 0) {
rc = RPMRC_OK;
}
+ if (pid != getpid()) {
+ /* Terminate child process forked in lua scriptlet */
+ rpmlog(RPMLOG_ERR, _("No exec() called after fork() in lua scriptlet\n"));
+ _exit(EXIT_FAILURE);
+ }
/* This failing would be fatal, return something different for it... */
if (fchdir(cwd)) {
rpmlog(RPMLOG_ERR, _("Unable to restore current directory: %m"));
@@ -93,22 +154,16 @@ static rpmRC runLuaScript(rpmPlugins plugins, int selinux, ARGV_const_t prefixes
static const char * const SCRIPT_PATH = "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin";
-static void doScriptExec(int selinux, ARGV_const_t argv, ARGV_const_t prefixes,
+static void doScriptExec(ARGV_const_t argv, ARGV_const_t prefixes,
FD_t scriptFd, FD_t out)
{
- int pipes[2];
int flag;
int fdno;
int xx;
int open_max;
+ /* SIGPIPE is ignored in rpm, reset to default for the scriptlet */
(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);
@@ -165,11 +220,6 @@ static void doScriptExec(int selinux, ARGV_const_t argv, ARGV_const_t prefixes,
/* XXX Don't mtrace into children. */
unsetenv("MALLOC_CHECK_");
- /* Permit libselinux to do the scriptlet exec. */
- if (selinux == 1) {
- xx = rpm_execcon(0, argv[0], argv, environ);
- }
-
if (xx == 0) {
xx = execv(argv[0], argv);
}
@@ -204,14 +254,19 @@ exit:
/**
* Run an external script.
*/
-static rpmRC runExtScript(rpmPlugins plugins, int selinux, ARGV_const_t prefixes,
+static rpmRC runExtScript(rpmPlugins plugins, ARGV_const_t prefixes,
const char *sname, rpmlogLvl lvl, FD_t scriptFd,
- ARGV_t * argvp, const char *script, int arg1, int arg2)
+ ARGV_t * argvp, const char *script, int arg1, int arg2,
+ scriptNextFileFunc nextFileFunc)
{
FD_t out = NULL;
char * fn = NULL;
pid_t pid, reaped;
int status;
+ int inpipe[2];
+ FILE *in = NULL;
+ const char *line;
+ char *mline = NULL;
rpmRC rc = RPMRC_FAIL;
rpmlog(RPMLOG_DEBUG, "%s: scriptlet start\n", sname);
@@ -234,6 +289,14 @@ static rpmRC runExtScript(rpmPlugins plugins, int selinux, ARGV_const_t prefixes
}
}
+ if (pipe(inpipe) < 0) {
+ rpmlog(RPMLOG_ERR,
+ ("Couldn't create pipe: %s\n"), strerror(errno));
+ goto exit;
+ }
+ in = fdopen(inpipe[1], "w");
+ inpipe[1] = 0;
+
if (scriptFd != NULL) {
if (rpmIsVerbose()) {
out = fdDup(Fileno(scriptFd));
@@ -261,13 +324,41 @@ static rpmRC runExtScript(rpmPlugins plugins, int selinux, ARGV_const_t prefixes
rpmlog(RPMLOG_DEBUG, "%s: execv(%s) pid %d\n",
sname, *argvp[0], (unsigned)getpid());
+ fclose(in);
+ dup2(inpipe[0], STDIN_FILENO);
+
/* Run scriptlet post fork hook for all plugins */
if (rpmpluginsCallScriptletForkPost(plugins, *argvp[0], RPMSCRIPTLET_FORK | RPMSCRIPTLET_EXEC) != RPMRC_FAIL) {
- doScriptExec(selinux, *argvp, prefixes, scriptFd, out);
+ doScriptExec(*argvp, prefixes, scriptFd, out);
} else {
_exit(126); /* exit 126 for compatibility with bash(1) */
}
}
+ close(inpipe[0]);
+ inpipe[0] = 0;
+
+ if (nextFileFunc->func) {
+ while ((line = nextFileFunc->func(nextFileFunc->param)) != NULL) {
+ size_t size = strlen(line);
+ size_t ret_size;
+ mline = xstrdup(line);
+ mline[size] = '\n';
+
+ ret_size = fwrite(mline, size + 1, 1, in);
+ mline = _free(mline);
+ if (ret_size != 1) {
+ if (errno == EPIPE) {
+ break;
+ } else {
+ rpmlog(RPMLOG_ERR, _("Fwrite failed: %s"), strerror(errno));
+ rc = RPMRC_FAIL;
+ goto exit;
+ }
+ }
+ }
+ }
+ fclose(in);
+ in = NULL;
do {
reaped = waitpid(pid, &status, 0);
@@ -293,6 +384,12 @@ static rpmRC runExtScript(rpmPlugins plugins, int selinux, ARGV_const_t prefixes
}
exit:
+ if (in)
+ fclose(in);
+
+ if (inpipe[0])
+ close(inpipe[0]);
+
if (out)
Fclose(out); /* XXX dup'd STDOUT_FILENO */
@@ -301,11 +398,13 @@ exit:
unlink(fn);
free(fn);
}
+ free(mline);
+
return rc;
}
rpmRC rpmScriptRun(rpmScript script, int arg1, int arg2, FD_t scriptFd,
- ARGV_const_t prefixes, int warn_only, int selinux, rpmPlugins plugins)
+ ARGV_const_t prefixes, int warn_only, rpmPlugins plugins)
{
ARGV_t args = NULL;
rpmlogLvl lvl = warn_only ? RPMLOG_WARNING : RPMLOG_ERR;
@@ -329,9 +428,9 @@ rpmRC rpmScriptRun(rpmScript script, int arg1, int arg2, FD_t scriptFd,
if (rc != RPMRC_FAIL) {
if (script_type & RPMSCRIPTLET_EXEC) {
- rc = runExtScript(plugins, selinux, prefixes, script->descr, lvl, scriptFd, &args, script->body, arg1, arg2);
+ rc = runExtScript(plugins, prefixes, script->descr, lvl, scriptFd, &args, script->body, arg1, arg2, &script->nextFileFunc);
} else {
- rc = runLuaScript(plugins, selinux, prefixes, script->descr, lvl, scriptFd, &args, script->body, arg1, arg2);
+ rc = runLuaScript(plugins, prefixes, script->descr, lvl, scriptFd, &args, script->body, arg1, arg2, &script->nextFileFunc);
}
}
@@ -343,54 +442,24 @@ rpmRC rpmScriptRun(rpmScript script, int arg1, int arg2, FD_t scriptFd,
return rc;
}
+static rpmscriptTypes getScriptType(rpmTagVal scriptTag)
+{
+ return findTag(scriptTag)->type;
+}
+
static rpmTagVal getProgTag(rpmTagVal 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;
- }
+ return findTag(scriptTag)->progtag;
}
static rpmTagVal getFlagTag(rpmTagVal scriptTag)
{
- switch (scriptTag) {
- case RPMTAG_PRETRANS: return RPMTAG_PRETRANSFLAGS;
- case RPMTAG_POSTTRANS: return RPMTAG_POSTTRANSFLAGS;
- case RPMTAG_PREUN: return RPMTAG_PREUNFLAGS;
- case RPMTAG_POSTUN: return RPMTAG_POSTUNFLAGS;
- case RPMTAG_PREIN: return RPMTAG_PREINFLAGS;
- case RPMTAG_POSTIN: return RPMTAG_POSTINFLAGS;
- case RPMTAG_VERIFYSCRIPT: return RPMTAG_VERIFYSCRIPTFLAGS;
- case RPMTAG_TRIGGERSCRIPTS: return RPMTAG_TRIGGERSCRIPTFLAGS;
- default:
- break;
- }
- return RPMTAG_NOT_FOUND;
+ return findTag(scriptTag)->flagtag;
}
static const char * tag2sln(rpmTagVal tag)
{
- switch (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";
+ return findTag(tag)->desc;
}
static rpmScript rpmScriptNew(Header h, rpmTagVal tag, const char *body,
@@ -399,6 +468,7 @@ static rpmScript rpmScriptNew(Header h, rpmTagVal tag, const char *body,
char *nevra = headerGetAsString(h, RPMTAG_NEVRA);
rpmScript script = xcalloc(1, sizeof(*script));
script->tag = tag;
+ script->type = getScriptType(tag);
script->flags = flags;
script->body = (body != NULL) ? xstrdup(body) : NULL;
rasprintf(&script->descr, "%s(%s)", tag2sln(tag), nevra);
@@ -416,20 +486,101 @@ static rpmScript rpmScriptNew(Header h, rpmTagVal tag, const char *body,
script->body = body;
}
+ script->nextFileFunc.func = NULL;
+ script->nextFileFunc.param = NULL;
+
free(nevra);
return script;
}
-rpmScript rpmScriptFromTriggerTag(Header h, rpmTagVal triggerTag, uint32_t ix)
+void rpmScriptSetNextFileFunc(rpmScript script, char *(*func)(void *),
+ void *param)
+{
+ script->nextFileFunc.func = func;
+ script->nextFileFunc.param = param;
+}
+
+rpmTagVal triggerDsTag(rpmscriptTriggerModes tm)
+{
+ rpmTagVal tag = RPMTAG_NOT_FOUND;
+ switch (tm) {
+ case RPMSCRIPT_NORMALTRIGGER:
+ tag = RPMTAG_TRIGGERNAME;
+ break;
+ case RPMSCRIPT_FILETRIGGER:
+ tag = RPMTAG_FILETRIGGERNAME;
+ break;
+ case RPMSCRIPT_TRANSFILETRIGGER:
+ tag = RPMTAG_TRANSFILETRIGGERNAME;
+ break;
+ }
+ return tag;
+}
+
+rpmscriptTriggerModes triggerMode(rpmTagVal tag)
+{
+ rpmscriptTriggerModes tm = 0;
+ switch (tag) {
+ case RPMTAG_TRIGGERNAME:
+ tm = RPMSCRIPT_NORMALTRIGGER;
+ break;
+ case RPMTAG_FILETRIGGERNAME:
+ tm = RPMSCRIPT_FILETRIGGER;
+ break;
+ case RPMTAG_TRANSFILETRIGGERNAME:
+ tm = RPMSCRIPT_TRANSFILETRIGGER;
+ break;
+ }
+ return tm;
+}
+
+rpmTagVal triggertag(rpmsenseFlags sense)
+{
+ rpmTagVal tag = RPMTAG_NOT_FOUND;
+ switch (sense) {
+ case RPMSENSE_TRIGGERIN:
+ tag = RPMTAG_TRIGGERIN;
+ break;
+ case RPMSENSE_TRIGGERUN:
+ tag = RPMTAG_TRIGGERUN;
+ break;
+ case RPMSENSE_TRIGGERPOSTUN:
+ tag = RPMTAG_TRIGGERPOSTUN;
+ break;
+ case RPMSENSE_TRIGGERPREIN:
+ tag = RPMTAG_TRIGGERPREIN;
+ break;
+ default:
+ break;
+ }
+ return tag;
+}
+
+rpmScript rpmScriptFromTriggerTag(Header h, rpmTagVal triggerTag,
+ rpmscriptTriggerModes tm, uint32_t ix)
{
rpmScript script = NULL;
struct rpmtd_s tscripts, tprogs, tflags;
headerGetFlags hgflags = HEADERGET_MINMEM;
- headerGet(h, RPMTAG_TRIGGERSCRIPTS, &tscripts, hgflags);
- headerGet(h, RPMTAG_TRIGGERSCRIPTPROG, &tprogs, hgflags);
- headerGet(h, RPMTAG_TRIGGERSCRIPTFLAGS, &tflags, hgflags);
-
+ switch (tm) {
+ case RPMSCRIPT_NORMALTRIGGER:
+ headerGet(h, RPMTAG_TRIGGERSCRIPTS, &tscripts, hgflags);
+ headerGet(h, RPMTAG_TRIGGERSCRIPTPROG, &tprogs, hgflags);
+ headerGet(h, RPMTAG_TRIGGERSCRIPTFLAGS, &tflags, hgflags);
+ break;
+ case RPMSCRIPT_FILETRIGGER:
+ headerGet(h, RPMTAG_FILETRIGGERSCRIPTS, &tscripts, hgflags);
+ headerGet(h, RPMTAG_FILETRIGGERSCRIPTPROG, &tprogs, hgflags);
+ headerGet(h, RPMTAG_FILETRIGGERSCRIPTFLAGS, &tflags, hgflags);
+ break;
+ case RPMSCRIPT_TRANSFILETRIGGER:
+ headerGet(h, RPMTAG_TRANSFILETRIGGERSCRIPTS, &tscripts, hgflags);
+ headerGet(h, RPMTAG_TRANSFILETRIGGERSCRIPTPROG, &tprogs, hgflags);
+ headerGet(h, RPMTAG_TRANSFILETRIGGERSCRIPTFLAGS, &tflags, hgflags);
+ break;
+ }
+
if (rpmtdSetIndex(&tscripts, ix) >= 0 && rpmtdSetIndex(&tprogs, ix) >= 0) {
rpmscriptFlags sflags = 0;
const char *prog = rpmtdGetString(&tprogs);
@@ -487,3 +638,8 @@ rpmTagVal rpmScriptTag(rpmScript script)
{
return (script != NULL) ? script->tag : RPMTAG_NOT_FOUND;
}
+
+rpmscriptTypes rpmScriptType(rpmScript script)
+{
+ return (script != NULL) ? script->type : 0;
+}