Blame lib/rpmscript.c

2ff057
#include "system.h"
2ff057
2ff057
#include <sys/types.h>
2ff057
#include <sys/wait.h>
2ff057
#include <errno.h>
2ff057
2ff057
#include <rpm/rpmfileutil.h>
2ff057
#include <rpm/rpmmacro.h>
2ff057
#include <rpm/rpmio.h>
2ff057
#include <rpm/rpmlog.h>
2ff057
#include <rpm/header.h>
2ff057
#include <rpm/rpmds.h>
2ff057
2ff057
#include "rpmio/rpmlua.h"
2ff057
#include "lib/rpmscript.h"
2ff057
#include "rpmio/rpmio_internal.h"
2ff057
2ff057
#include "lib/rpmplugins.h"     /* rpm plugins hooks */
2ff057
2ff057
#include "debug.h"
2ff057
2ff057
struct scriptNextFileFunc_s {
2ff057
    char *(*func)(void *);	/* function producing input for script */
2ff057
    void *param;		/* parameter for func */
2ff057
};
2ff057
2ff057
typedef struct scriptNextFileFunc_s *scriptNextFileFunc;
2ff057
2ff057
struct rpmScript_s {
2ff057
    rpmscriptTypes type;	/* script type */
2ff057
    rpmTagVal tag;		/* script tag */
2ff057
    char **args;		/* scriptlet call arguments */
2ff057
    char *body;			/* script body */
2ff057
    char *descr;		/* description for logging */
2ff057
    rpmscriptFlags flags;	/* flags to control operation */
2ff057
    struct scriptNextFileFunc_s nextFileFunc;  /* input function */
2ff057
};
2ff057
2ff057
struct scriptInfo_s {
2ff057
    rpmscriptTypes type;
2ff057
    const char *desc;
2ff057
    rpmsenseFlags sense;
2ff057
    rpmTagVal tag;
2ff057
    rpmTagVal progtag;
2ff057
    rpmTagVal flagtag;
2ff057
};
2ff057
2ff057
static const struct scriptInfo_s scriptInfo[] = {
2ff057
    { RPMSCRIPT_PREIN, "%prein", 0,
2ff057
	RPMTAG_PREIN, RPMTAG_PREINPROG, RPMTAG_PREINFLAGS },
2ff057
    { RPMSCRIPT_PREUN, "%preun", 0,
2ff057
	RPMTAG_PREUN, RPMTAG_PREUNPROG, RPMTAG_PREUNFLAGS },
2ff057
    { RPMSCRIPT_POSTIN, "%post", 0,
2ff057
	RPMTAG_POSTIN, RPMTAG_POSTINPROG, RPMTAG_POSTINFLAGS },
2ff057
    { RPMSCRIPT_POSTUN, "%postun", 0,
2ff057
	RPMTAG_POSTUN, RPMTAG_POSTUNPROG, RPMTAG_POSTUNFLAGS },
2ff057
    { RPMSCRIPT_PRETRANS, "%pretrans", 0,
2ff057
	RPMTAG_PRETRANS, RPMTAG_PRETRANSPROG, RPMTAG_PRETRANSFLAGS },
2ff057
    { RPMSCRIPT_POSTTRANS, "%posttrans", 0,
2ff057
	RPMTAG_POSTTRANS, RPMTAG_POSTTRANSPROG, RPMTAG_POSTTRANSFLAGS },
2ff057
    { RPMSCRIPT_TRIGGERPREIN, "%triggerprein", RPMSENSE_TRIGGERPREIN,
2ff057
	RPMTAG_TRIGGERPREIN, 0, 0 },
2ff057
    { RPMSCRIPT_TRIGGERUN, "%triggerun", RPMSENSE_TRIGGERUN,
2ff057
	RPMTAG_TRIGGERUN, 0, 0 },
2ff057
    { RPMSCRIPT_TRIGGERIN, "%triggerin", RPMSENSE_TRIGGERIN,
2ff057
	RPMTAG_TRIGGERIN, 0, 0 },
2ff057
    { RPMSCRIPT_TRIGGERPOSTUN, "%triggerpostun", RPMSENSE_TRIGGERPOSTUN,
2ff057
	RPMTAG_TRIGGERPOSTUN, 0, 0 },
2ff057
    { RPMSCRIPT_VERIFY, "%verify", 0,
2ff057
	RPMTAG_VERIFYSCRIPT, RPMTAG_VERIFYSCRIPTPROG, RPMTAG_VERIFYSCRIPTFLAGS},
2ff057
    { 0, "unknown", 0,
2ff057
	RPMTAG_NOT_FOUND, RPMTAG_NOT_FOUND, RPMTAG_NOT_FOUND }
2ff057
};
2ff057
2ff057
static const struct scriptInfo_s * findTag(rpmTagVal tag)
2ff057
{
2ff057
    const struct scriptInfo_s * si = scriptInfo;
2ff057
    while (si->type && si->tag != tag)
2ff057
	si++;
2ff057
    return si;
2ff057
}
2ff057
/**
2ff057
 * Run internal Lua script.
2ff057
 */
2ff057
static rpmRC runLuaScript(rpmPlugins plugins, ARGV_const_t prefixes,
2ff057
		   const char *sname, rpmlogLvl lvl, FD_t scriptFd,
2ff057
		   ARGV_t * argvp, const char *script, int arg1, int arg2,
2ff057
		   scriptNextFileFunc nextFileFunc)
2ff057
{
2ff057
    rpmRC rc = RPMRC_FAIL;
2ff057
#ifdef WITH_LUA
2ff057
    ARGV_t argv = argvp ? *argvp : NULL;
2ff057
    rpmlua lua = NULL; /* Global state. */
2ff057
    rpmluav var = rpmluavNew();
2ff057
    int cwd = -1;
2ff057
2ff057
    rpmlog(RPMLOG_DEBUG, "%s: running <lua> scriptlet.\n", sname);
2ff057
2ff057
    /* Create arg variable */
2ff057
    rpmluaPushTable(lua, "arg");
2ff057
    rpmluavSetListMode(var, 1);
2ff057
    rpmluaSetNextFileFunc(nextFileFunc->func, nextFileFunc->param);
2ff057
    if (argv) {
2ff057
	char **p;
2ff057
	for (p = argv; *p; p++) {
2ff057
	    rpmluavSetValue(var, RPMLUAV_STRING, *p);
2ff057
	    rpmluaSetVar(lua, var);
2ff057
	}
2ff057
    }
2ff057
    if (arg1 >= 0) {
2ff057
	rpmluavSetValueNum(var, arg1);
2ff057
	rpmluaSetVar(lua, var);
2ff057
    }
2ff057
    if (arg2 >= 0) {
2ff057
	rpmluavSetValueNum(var, arg2);
2ff057
	rpmluaSetVar(lua, var);
2ff057
    }
2ff057
    rpmluaPop(lua);
2ff057
2ff057
    /* Lua scripts can change our cwd and umask, save and restore */
2ff057
    /* XXX TODO: use cwd from chroot state to save unnecessary open here */
2ff057
    cwd = open(".", O_RDONLY);
2ff057
    if (cwd != -1) {
2ff057
	mode_t oldmask = umask(0);
2ff057
	umask(oldmask);
2ff057
	pid_t pid = getpid();
2ff057
2ff057
	if (chdir("/") == 0 && rpmluaRunScript(lua, script, sname) == 0) {
2ff057
	    rc = RPMRC_OK;
2ff057
	}
2ff057
	if (pid != getpid()) {
2ff057
	    /* Terminate child process forked in lua scriptlet */
2ff057
	    rpmlog(RPMLOG_ERR, _("No exec() called after fork() in lua scriptlet\n"));
2ff057
	    _exit(EXIT_FAILURE);
2ff057
	}
2ff057
	/* This failing would be fatal, return something different for it... */
2ff057
	if (fchdir(cwd)) {
2ff057
	    rpmlog(RPMLOG_ERR, _("Unable to restore current directory: %m"));
2ff057
	    rc = RPMRC_NOTFOUND;
2ff057
	}
2ff057
	close(cwd);
2ff057
	umask(oldmask);
2ff057
    }
2ff057
2ff057
    rpmluaDelVar(lua, "arg");
2ff057
    rpmluavFree(var);
2ff057
2ff057
#else
2ff057
    rpmlog(lvl, _("<lua> scriptlet support not built in\n"));
2ff057
#endif
2ff057
2ff057
    return rc;
2ff057
}
2ff057
2ff057
static const char * const SCRIPT_PATH = "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin";
2ff057
2ff057
static void doScriptExec(ARGV_const_t argv, ARGV_const_t prefixes,
2ff057
			FD_t scriptFd, FD_t out)
2ff057
{
2ff057
    int xx;
2ff057
2ff057
    /* SIGPIPE is ignored in rpm, reset to default for the scriptlet */
2ff057
    (void) signal(SIGPIPE, SIG_DFL);
2ff057
2ff057
    rpmSetCloseOnExec();
2ff057
2ff057
    if (scriptFd != NULL) {
2ff057
	int sfdno = Fileno(scriptFd);
2ff057
	int ofdno = Fileno(out);
2ff057
	if (sfdno != STDERR_FILENO)
2ff057
	    xx = dup2(sfdno, STDERR_FILENO);
2ff057
	if (ofdno != STDOUT_FILENO)
2ff057
	    xx = dup2(ofdno, STDOUT_FILENO);
2ff057
	/* make sure we don't close stdin/stderr/stdout by mistake! */
2ff057
	if (ofdno > STDERR_FILENO && ofdno != sfdno)
2ff057
	    xx = Fclose (out);
2ff057
	if (sfdno > STDERR_FILENO && ofdno != sfdno)
2ff057
	    xx = Fclose (scriptFd);
2ff057
    }
2ff057
2ff057
    {   char *ipath = rpmExpand("%{_install_script_path}", NULL);
2ff057
	const char *path = SCRIPT_PATH;
2ff057
2ff057
	if (ipath && ipath[5] != '%')
2ff057
	    path = ipath;
2ff057
2ff057
	xx = setenv("PATH", path, 1);
2ff057
	free(ipath);
2ff057
    }
2ff057
2ff057
    for (ARGV_const_t pf = prefixes; pf && *pf; pf++) {
2ff057
	char *name = NULL;
2ff057
	int num = (pf - prefixes);
2ff057
2ff057
	rasprintf(&name, "RPM_INSTALL_PREFIX%d", num);
2ff057
	setenv(name, *pf, 1);
2ff057
	free(name);
2ff057
2ff057
	/* scripts might still be using the old style prefix */
2ff057
	if (num == 0) {
2ff057
	    setenv("RPM_INSTALL_PREFIX", *pf, 1);
2ff057
	}
2ff057
    }
2ff057
	
2ff057
    if (chdir("/") == 0) {
2ff057
	/* XXX Don't mtrace into children. */
2ff057
	unsetenv("MALLOC_CHECK_");
2ff057
2ff057
	xx = execv(argv[0], argv);
2ff057
	if (xx) {
2ff057
	    rpmlog(RPMLOG_ERR,
2ff057
		    _("failed to exec scriptlet interpreter %s: %s\n"),
2ff057
		    argv[0], strerror(errno));
2ff057
	}
2ff057
    }
2ff057
    _exit(127); /* exit 127 for compatibility with bash(1) */
2ff057
}
2ff057
2ff057
static char * writeScript(const char *cmd, const char *script)
2ff057
{
2ff057
    char *fn = NULL;
2ff057
    size_t slen = strlen(script);
2ff057
    int ok = 0;
2ff057
    FD_t fd = rpmMkTempFile("/", &fn);
2ff057
2ff057
    if (Ferror(fd))
2ff057
	goto exit;
2ff057
2ff057
    if (rpmIsDebug() && (rstreq(cmd, "/bin/sh") || rstreq(cmd, "/bin/bash"))) {
2ff057
	static const char set_x[] = "set -x\n";
2ff057
	/* Assume failures will be caught by the write below */
2ff057
	Fwrite(set_x, sizeof(set_x[0]), sizeof(set_x)-1, fd);
2ff057
    }
2ff057
2ff057
    ok = (Fwrite(script, sizeof(script[0]), slen, fd) == slen);
2ff057
2ff057
exit:
2ff057
    if (!ok) fn = _free(fn);
2ff057
    Fclose(fd);
2ff057
    return fn;
2ff057
}
2ff057
2ff057
/**
2ff057
 * Run an external script.
2ff057
 */
2ff057
static rpmRC runExtScript(rpmPlugins plugins, ARGV_const_t prefixes,
2ff057
		   const char *sname, rpmlogLvl lvl, FD_t scriptFd,
2ff057
		   ARGV_t * argvp, const char *script, int arg1, int arg2,
2ff057
		   scriptNextFileFunc nextFileFunc)
2ff057
{
2ff057
    FD_t out = NULL;
2ff057
    char * fn = NULL;
2ff057
    pid_t pid, reaped;
2ff057
    int status;
2ff057
    int inpipe[2];
2ff057
    FILE *in = NULL;
2ff057
    const char *line;
2ff057
    char *mline = NULL;
2ff057
    rpmRC rc = RPMRC_FAIL;
2ff057
2ff057
    rpmlog(RPMLOG_DEBUG, "%s: scriptlet start\n", sname);
2ff057
2ff057
    if (script) {
2ff057
	fn = writeScript(*argvp[0], script);
2ff057
	if (fn == NULL) {
2ff057
	    rpmlog(RPMLOG_ERR,
2ff057
		   _("Couldn't create temporary file for %s: %s\n"),
2ff057
		   sname, strerror(errno));
2ff057
	    goto exit;
2ff057
	}
2ff057
2ff057
	argvAdd(argvp, fn);
2ff057
	if (arg1 >= 0) {
2ff057
	    argvAddNum(argvp, arg1);
2ff057
	}
2ff057
	if (arg2 >= 0) {
2ff057
	    argvAddNum(argvp, arg2);
2ff057
	}
2ff057
    }
2ff057
2ff057
    if (pipe(inpipe) < 0) {
2ff057
	rpmlog(RPMLOG_ERR,
2ff057
		("Couldn't create pipe: %s\n"), strerror(errno));
2ff057
	goto exit;
2ff057
    }
2ff057
    in = fdopen(inpipe[1], "w");
2ff057
    inpipe[1] = 0;
2ff057
2ff057
    if (scriptFd != NULL) {
2ff057
	if (rpmIsVerbose()) {
2ff057
	    out = fdDup(Fileno(scriptFd));
2ff057
	} else {
2ff057
	    out = Fopen("/dev/null", "w.fdio");
2ff057
	    if (Ferror(out)) {
2ff057
		out = fdDup(Fileno(scriptFd));
2ff057
	    }
2ff057
	}
2ff057
    } else {
2ff057
	out = fdDup(STDOUT_FILENO);
2ff057
    }
2ff057
    if (out == NULL) { 
2ff057
	rpmlog(RPMLOG_ERR, _("Couldn't duplicate file descriptor: %s: %s\n"),
2ff057
	       sname, strerror(errno));
2ff057
	goto exit;
2ff057
    }
2ff057
2ff057
    pid = fork();
2ff057
    if (pid == (pid_t) -1) {
2ff057
	rpmlog(RPMLOG_ERR, _("Couldn't fork %s: %s\n"),
2ff057
		sname, strerror(errno));
2ff057
	goto exit;
2ff057
    } else if (pid == 0) {/* Child */
2ff057
	rpmlog(RPMLOG_DEBUG, "%s: execv(%s) pid %d\n",
2ff057
	       sname, *argvp[0], (unsigned)getpid());
2ff057
2ff057
	fclose(in);
2ff057
	dup2(inpipe[0], STDIN_FILENO);
2ff057
2ff057
	/* Run scriptlet post fork hook for all plugins */
2ff057
	if (rpmpluginsCallScriptletForkPost(plugins, *argvp[0], RPMSCRIPTLET_FORK | RPMSCRIPTLET_EXEC) != RPMRC_FAIL) {
2ff057
	    doScriptExec(*argvp, prefixes, scriptFd, out);
2ff057
	} else {
2ff057
	    _exit(126); /* exit 126 for compatibility with bash(1) */
2ff057
	}
2ff057
    }
2ff057
    close(inpipe[0]);
2ff057
    inpipe[0] = 0;
2ff057
2ff057
    if (nextFileFunc->func) {
2ff057
	while ((line = nextFileFunc->func(nextFileFunc->param)) != NULL) {
2ff057
	    size_t size = strlen(line);
2ff057
	    size_t ret_size;
2ff057
	    mline = xstrdup(line);
2ff057
	    mline[size] = '\n';
2ff057
2ff057
	    ret_size = fwrite(mline, size + 1, 1, in);
2ff057
	    mline = _free(mline);
2ff057
	    if (ret_size != 1) {
2ff057
		if (errno == EPIPE) {
2ff057
		    break;
2ff057
		} else {
2ff057
		    rpmlog(RPMLOG_ERR, _("Fwrite failed: %s"), strerror(errno));
2ff057
		    rc = RPMRC_FAIL;
2ff057
		    goto exit;
2ff057
		}
2ff057
	    }
2ff057
	}
2ff057
    }
2ff057
    fclose(in);
2ff057
    in = NULL;
2ff057
2ff057
    do {
2ff057
	reaped = waitpid(pid, &status, 0);
2ff057
    } while (reaped == -1 && errno == EINTR);
2ff057
2ff057
    rpmlog(RPMLOG_DEBUG, "%s: waitpid(%d) rc %d status %x\n",
2ff057
	   sname, (unsigned)pid, (unsigned)reaped, status);
2ff057
2ff057
    if (reaped < 0) {
2ff057
	rpmlog(lvl, _("%s scriptlet failed, waitpid(%d) rc %d: %s\n"),
2ff057
		 sname, pid, reaped, strerror(errno));
2ff057
    } else if (!WIFEXITED(status) || WEXITSTATUS(status)) {
2ff057
      	if (WIFSIGNALED(status)) {
2ff057
	    rpmlog(lvl, _("%s scriptlet failed, signal %d\n"),
2ff057
                   sname, WTERMSIG(status));
2ff057
	} else {
2ff057
	    rpmlog(lvl, _("%s scriptlet failed, exit status %d\n"),
2ff057
		   sname, WEXITSTATUS(status));
2ff057
	}
2ff057
    } else {
2ff057
	/* if we get this far we're clear */
2ff057
	rc = RPMRC_OK;
2ff057
    }
2ff057
2ff057
exit:
2ff057
    if (in)
2ff057
	fclose(in);
2ff057
2ff057
    if (inpipe[0])
2ff057
	close(inpipe[0]);
2ff057
2ff057
    if (out)
2ff057
	Fclose(out);	/* XXX dup'd STDOUT_FILENO */
2ff057
2ff057
    if (fn) {
2ff057
	if (!rpmIsDebug())
2ff057
	    unlink(fn);
2ff057
	free(fn);
2ff057
    }
2ff057
    free(mline);
2ff057
2ff057
    return rc;
2ff057
}
2ff057
2ff057
rpmRC rpmScriptRun(rpmScript script, int arg1, int arg2, FD_t scriptFd,
2ff057
		   ARGV_const_t prefixes, int warn_only, rpmPlugins plugins)
2ff057
{
2ff057
    ARGV_t args = NULL;
2ff057
    rpmlogLvl lvl = warn_only ? RPMLOG_WARNING : RPMLOG_ERR;
2ff057
    rpmRC rc;
2ff057
    int script_type = RPMSCRIPTLET_FORK | RPMSCRIPTLET_EXEC;
2ff057
2ff057
    if (script == NULL) return RPMRC_OK;
2ff057
2ff057
    /* construct a new argv as we can't modify the one from header */
2ff057
    if (script->args) {
2ff057
	argvAppend(&args, script->args);
2ff057
    } else {
2ff057
	argvAdd(&args, "/bin/sh");
2ff057
    }
2ff057
    
2ff057
    if (rstreq(args[0], "<lua>"))
2ff057
	script_type = RPMSCRIPTLET_NONE;
2ff057
2ff057
    /* Run scriptlet pre hook for all plugins */
2ff057
    rc = rpmpluginsCallScriptletPre(plugins, script->descr, script_type);
2ff057
2ff057
    if (rc != RPMRC_FAIL) {
2ff057
	if (script_type & RPMSCRIPTLET_EXEC) {
2ff057
	    rc = runExtScript(plugins, prefixes, script->descr, lvl, scriptFd, &args, script->body, arg1, arg2, &script->nextFileFunc);
2ff057
	} else {
2ff057
	    rc = runLuaScript(plugins, prefixes, script->descr, lvl, scriptFd, &args, script->body, arg1, arg2, &script->nextFileFunc);
2ff057
	}
2ff057
    }
2ff057
2ff057
    /* Run scriptlet post hook for all plugins */
2ff057
    rpmpluginsCallScriptletPost(plugins, script->descr, script_type, rc);
2ff057
2ff057
    argvFree(args);
2ff057
2ff057
    return rc;
2ff057
}
2ff057
2ff057
static rpmscriptTypes getScriptType(rpmTagVal scriptTag)
2ff057
{
2ff057
    return findTag(scriptTag)->type;
2ff057
}
2ff057
2ff057
static rpmTagVal getProgTag(rpmTagVal scriptTag)
2ff057
{
2ff057
    return findTag(scriptTag)->progtag;
2ff057
}
2ff057
2ff057
static rpmTagVal getFlagTag(rpmTagVal scriptTag)
2ff057
{
2ff057
    return findTag(scriptTag)->flagtag;
2ff057
}
2ff057
2ff057
static const char * tag2sln(rpmTagVal tag)
2ff057
{
2ff057
    return findTag(tag)->desc;
2ff057
}
2ff057
2ff057
static rpmScript rpmScriptNew(Header h, rpmTagVal tag, const char *body,
2ff057
			      rpmscriptFlags flags)
2ff057
{
2ff057
    char *nevra = headerGetAsString(h, RPMTAG_NEVRA);
2ff057
    rpmScript script = xcalloc(1, sizeof(*script));
2ff057
    script->tag = tag;
2ff057
    script->type = getScriptType(tag);
2ff057
    script->flags = flags;
2ff057
    script->body = (body != NULL) ? xstrdup(body) : NULL;
2ff057
    rasprintf(&script->descr, "%s(%s)", tag2sln(tag), nevra);
2ff057
2ff057
    /* macros need to be expanded before possible queryformat */
2ff057
    if (script->body && (script->flags & RPMSCRIPT_FLAG_EXPAND)) {
2ff057
	char *body = rpmExpand(script->body, NULL);
2ff057
	free(script->body);
2ff057
	script->body = body;
2ff057
    }
2ff057
    if (script->body && (script->flags & RPMSCRIPT_FLAG_QFORMAT)) {
2ff057
	/* XXX TODO: handle queryformat errors */
2ff057
	char *body = headerFormat(h, script->body, NULL);
2ff057
	free(script->body);
2ff057
	script->body = body;
2ff057
    }
2ff057
2ff057
    script->nextFileFunc.func = NULL;
2ff057
    script->nextFileFunc.param = NULL;
2ff057
2ff057
    free(nevra);
2ff057
    return script;
2ff057
}
2ff057
2ff057
void rpmScriptSetNextFileFunc(rpmScript script, char *(*func)(void *),
2ff057
			    void *param)
2ff057
{
2ff057
    script->nextFileFunc.func = func;
2ff057
    script->nextFileFunc.param = param;
2ff057
}
2ff057
2ff057
rpmTagVal triggerDsTag(rpmscriptTriggerModes tm)
2ff057
{
2ff057
    rpmTagVal tag = RPMTAG_NOT_FOUND;
2ff057
    switch (tm) {
2ff057
    case RPMSCRIPT_NORMALTRIGGER:
2ff057
	tag = RPMTAG_TRIGGERNAME;
2ff057
	break;
2ff057
    case RPMSCRIPT_FILETRIGGER:
2ff057
	tag = RPMTAG_FILETRIGGERNAME;
2ff057
	break;
2ff057
    case RPMSCRIPT_TRANSFILETRIGGER:
2ff057
	tag = RPMTAG_TRANSFILETRIGGERNAME;
2ff057
	break;
2ff057
    }
2ff057
    return tag;
2ff057
}
2ff057
2ff057
rpmscriptTriggerModes triggerMode(rpmTagVal tag)
2ff057
{
2ff057
    rpmscriptTriggerModes tm = 0;
2ff057
    switch (tag) {
2ff057
    case RPMTAG_TRIGGERNAME:
2ff057
	tm = RPMSCRIPT_NORMALTRIGGER;
2ff057
	break;
2ff057
    case RPMTAG_FILETRIGGERNAME:
2ff057
	tm = RPMSCRIPT_FILETRIGGER;
2ff057
	break;
2ff057
    case RPMTAG_TRANSFILETRIGGERNAME:
2ff057
	tm = RPMSCRIPT_TRANSFILETRIGGER;
2ff057
	break;
2ff057
    }
2ff057
    return tm;
2ff057
}
2ff057
2ff057
rpmTagVal triggertag(rpmsenseFlags sense)
2ff057
{
2ff057
    rpmTagVal tag = RPMTAG_NOT_FOUND;
2ff057
    switch (sense) {
2ff057
    case RPMSENSE_TRIGGERIN:
2ff057
	tag = RPMTAG_TRIGGERIN;
2ff057
	break;
2ff057
    case RPMSENSE_TRIGGERUN:
2ff057
	tag = RPMTAG_TRIGGERUN;
2ff057
	break;
2ff057
    case RPMSENSE_TRIGGERPOSTUN:
2ff057
	tag = RPMTAG_TRIGGERPOSTUN;
2ff057
	break;
2ff057
    case RPMSENSE_TRIGGERPREIN:
2ff057
	tag = RPMTAG_TRIGGERPREIN;
2ff057
	break;
2ff057
    default:
2ff057
	break;
2ff057
    }
2ff057
    return tag;
2ff057
}
2ff057
2ff057
rpmScript rpmScriptFromTriggerTag(Header h, rpmTagVal triggerTag,
2ff057
			    rpmscriptTriggerModes tm, uint32_t ix)
2ff057
{
2ff057
    rpmScript script = NULL;
2ff057
    struct rpmtd_s tscripts, tprogs, tflags;
2ff057
    headerGetFlags hgflags = HEADERGET_MINMEM;
2ff057
2ff057
    switch (tm) {
2ff057
	case RPMSCRIPT_NORMALTRIGGER:
2ff057
	    headerGet(h, RPMTAG_TRIGGERSCRIPTS, &tscripts, hgflags);
2ff057
	    headerGet(h, RPMTAG_TRIGGERSCRIPTPROG, &tprogs, hgflags);
2ff057
	    headerGet(h, RPMTAG_TRIGGERSCRIPTFLAGS, &tflags, hgflags);
2ff057
	    break;
2ff057
	case RPMSCRIPT_FILETRIGGER:
2ff057
	    headerGet(h, RPMTAG_FILETRIGGERSCRIPTS, &tscripts, hgflags);
2ff057
	    headerGet(h, RPMTAG_FILETRIGGERSCRIPTPROG, &tprogs, hgflags);
2ff057
	    headerGet(h, RPMTAG_FILETRIGGERSCRIPTFLAGS, &tflags, hgflags);
2ff057
	    break;
2ff057
	case RPMSCRIPT_TRANSFILETRIGGER:
2ff057
	    headerGet(h, RPMTAG_TRANSFILETRIGGERSCRIPTS, &tscripts, hgflags);
2ff057
	    headerGet(h, RPMTAG_TRANSFILETRIGGERSCRIPTPROG, &tprogs, hgflags);
2ff057
	    headerGet(h, RPMTAG_TRANSFILETRIGGERSCRIPTFLAGS, &tflags, hgflags);
2ff057
	    break;
2ff057
    }
2ff057
2ff057
    if (rpmtdSetIndex(&tscripts, ix) >= 0 && rpmtdSetIndex(&tprogs, ix) >= 0) {
2ff057
	rpmscriptFlags sflags = 0;
2ff057
	const char *prog = rpmtdGetString(&tprogs);
2ff057
2ff057
	if (rpmtdSetIndex(&tflags, ix) >= 0)
2ff057
	    sflags = rpmtdGetNumber(&tflags);
2ff057
2ff057
	script = rpmScriptNew(h, triggerTag, rpmtdGetString(&tscripts), sflags);
2ff057
2ff057
	/* hack up a hge-style NULL-terminated array */
2ff057
	script->args = xmalloc(2 * sizeof(*script->args) + strlen(prog) + 1);
2ff057
	script->args[0] = (char *)(script->args + 2);
2ff057
	script->args[1] = NULL;
2ff057
	strcpy(script->args[0], prog);
2ff057
    }
2ff057
2ff057
    rpmtdFreeData(&tscripts);
2ff057
    rpmtdFreeData(&tprogs);
2ff057
    rpmtdFreeData(&tflags);
2ff057
2ff057
    return script;
2ff057
}
2ff057
2ff057
rpmScript rpmScriptFromTag(Header h, rpmTagVal scriptTag)
2ff057
{
2ff057
    rpmScript script = NULL;
2ff057
    rpmTagVal progTag = getProgTag(scriptTag);
2ff057
2ff057
    if (headerIsEntry(h, scriptTag) || headerIsEntry(h, progTag)) {
2ff057
	struct rpmtd_s prog;
2ff057
2ff057
	script = rpmScriptNew(h, scriptTag,
2ff057
			      headerGetString(h, scriptTag),
2ff057
			      headerGetNumber(h, getFlagTag(scriptTag)));
2ff057
2ff057
	if (headerGet(h, progTag, &prog, (HEADERGET_ALLOC|HEADERGET_ARGV))) {
2ff057
	    script->args = prog.data;
2ff057
	}
2ff057
    }
2ff057
    return script;
2ff057
}
2ff057
2ff057
rpmScript rpmScriptFree(rpmScript script)
2ff057
{
2ff057
    if (script) {
2ff057
	free(script->args);
2ff057
	free(script->body);
2ff057
	free(script->descr);
2ff057
	free(script);
2ff057
    }
2ff057
    return NULL;
2ff057
}
2ff057
2ff057
rpmTagVal rpmScriptTag(rpmScript script)
2ff057
{
2ff057
    return (script != NULL) ? script->tag : RPMTAG_NOT_FOUND;
2ff057
}
2ff057
2ff057
rpmscriptTypes rpmScriptType(rpmScript script)
2ff057
{
2ff057
    return (script != NULL) ? script->type : 0;
2ff057
}