"Fossies" - the Fresh Open Source Software Archive

Member "rpm-4.15.1/lib/rpmscript.c" (26 Jun 2019, 16954 Bytes) of package /linux/misc/rpm-4.15.1.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "rpmscript.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 4.14.2.1_vs_4.15.0-rc1.

    1 #include "system.h"
    2 
    3 #include <sys/types.h>
    4 #include <sys/wait.h>
    5 #include <errno.h>
    6 
    7 #include <rpm/rpmfileutil.h>
    8 #include <rpm/rpmmacro.h>
    9 #include <rpm/rpmio.h>
   10 #include <rpm/rpmlog.h>
   11 #include <rpm/header.h>
   12 #include <rpm/rpmds.h>
   13 
   14 #include "rpmio/rpmlua.h"
   15 #include "lib/rpmscript.h"
   16 #include "rpmio/rpmio_internal.h"
   17 
   18 #include "lib/rpmplugins.h"     /* rpm plugins hooks */
   19 
   20 #include "debug.h"
   21 
   22 struct scriptNextFileFunc_s {
   23     char *(*func)(void *);  /* function producing input for script */
   24     void *param;        /* parameter for func */
   25 };
   26 
   27 typedef struct scriptNextFileFunc_s *scriptNextFileFunc;
   28 
   29 struct rpmScript_s {
   30     rpmscriptTypes type;    /* script type */
   31     rpmTagVal tag;      /* script tag */
   32     char **args;        /* scriptlet call arguments */
   33     char *body;         /* script body */
   34     char *descr;        /* description for logging */
   35     rpmscriptFlags flags;   /* flags to control operation */
   36     struct scriptNextFileFunc_s nextFileFunc;  /* input function */
   37 };
   38 
   39 struct scriptInfo_s {
   40     rpmscriptTypes type;
   41     const char *desc;
   42     rpmsenseFlags sense;
   43     rpmTagVal tag;
   44     rpmTagVal progtag;
   45     rpmTagVal flagtag;
   46     rpmscriptFlags deflags;
   47 };
   48 
   49 static const struct scriptInfo_s scriptInfo[] = {
   50     { RPMSCRIPT_PREIN, "%prein", 0,
   51     RPMTAG_PREIN, RPMTAG_PREINPROG, RPMTAG_PREINFLAGS,
   52     RPMSCRIPT_FLAG_CRITICAL, },
   53     { RPMSCRIPT_PREUN, "%preun", 0,
   54     RPMTAG_PREUN, RPMTAG_PREUNPROG, RPMTAG_PREUNFLAGS,
   55     RPMSCRIPT_FLAG_CRITICAL, },
   56     { RPMSCRIPT_POSTIN, "%post", 0,
   57     RPMTAG_POSTIN, RPMTAG_POSTINPROG, RPMTAG_POSTINFLAGS,
   58     0, },
   59     { RPMSCRIPT_POSTUN, "%postun", 0,
   60     RPMTAG_POSTUN, RPMTAG_POSTUNPROG, RPMTAG_POSTUNFLAGS,
   61     0, },
   62     { RPMSCRIPT_PRETRANS, "%pretrans", 0,
   63     RPMTAG_PRETRANS, RPMTAG_PRETRANSPROG, RPMTAG_PRETRANSFLAGS,
   64     RPMSCRIPT_FLAG_CRITICAL, },
   65     { RPMSCRIPT_POSTTRANS, "%posttrans", 0,
   66     RPMTAG_POSTTRANS, RPMTAG_POSTTRANSPROG, RPMTAG_POSTTRANSFLAGS,
   67     0, },
   68     { RPMSCRIPT_TRIGGERPREIN, "%triggerprein", RPMSENSE_TRIGGERPREIN,
   69     RPMTAG_TRIGGERPREIN, 0, 0,
   70     0, },
   71     { RPMSCRIPT_TRIGGERUN, "%triggerun", RPMSENSE_TRIGGERUN,
   72     RPMTAG_TRIGGERUN, 0, 0,
   73     0, },
   74     { RPMSCRIPT_TRIGGERIN, "%triggerin", RPMSENSE_TRIGGERIN,
   75     RPMTAG_TRIGGERIN, 0, 0,
   76     0, },
   77     { RPMSCRIPT_TRIGGERPOSTUN, "%triggerpostun", RPMSENSE_TRIGGERPOSTUN,
   78     RPMTAG_TRIGGERPOSTUN, 0, 0,
   79     0, },
   80     { RPMSCRIPT_VERIFY, "%verify", 0,
   81     RPMTAG_VERIFYSCRIPT, RPMTAG_VERIFYSCRIPTPROG, RPMTAG_VERIFYSCRIPTFLAGS,
   82     RPMSCRIPT_FLAG_CRITICAL, },
   83     { 0, "unknown", 0,
   84     RPMTAG_NOT_FOUND, RPMTAG_NOT_FOUND, RPMTAG_NOT_FOUND,
   85     0, }
   86 };
   87 
   88 static const struct scriptInfo_s * findTag(rpmTagVal tag)
   89 {
   90     const struct scriptInfo_s * si = scriptInfo;
   91     while (si->type && si->tag != tag)
   92     si++;
   93     return si;
   94 }
   95 /**
   96  * Run internal Lua script.
   97  */
   98 static rpmRC runLuaScript(rpmPlugins plugins, ARGV_const_t prefixes,
   99            const char *sname, rpmlogLvl lvl, FD_t scriptFd,
  100            ARGV_t * argvp, const char *script, int arg1, int arg2,
  101            scriptNextFileFunc nextFileFunc)
  102 {
  103     rpmRC rc = RPMRC_FAIL;
  104 #ifdef WITH_LUA
  105     ARGV_t argv = argvp ? *argvp : NULL;
  106     rpmlua lua = NULL; /* Global state. */
  107     rpmluav var = rpmluavNew();
  108     int cwd = -1;
  109 
  110     rpmlog(RPMLOG_DEBUG, "%s: running <lua> scriptlet.\n", sname);
  111 
  112     /* Create arg variable */
  113     rpmluaPushTable(lua, "arg");
  114     rpmluavSetListMode(var, 1);
  115     rpmluaSetNextFileFunc(nextFileFunc->func, nextFileFunc->param);
  116     if (argv) {
  117     char **p;
  118     for (p = argv; *p; p++) {
  119         rpmluavSetValue(var, RPMLUAV_STRING, *p);
  120         rpmluaSetVar(lua, var);
  121     }
  122     }
  123     if (arg1 >= 0) {
  124     rpmluavSetValueNum(var, arg1);
  125     rpmluaSetVar(lua, var);
  126     }
  127     if (arg2 >= 0) {
  128     rpmluavSetValueNum(var, arg2);
  129     rpmluaSetVar(lua, var);
  130     }
  131     rpmluaPop(lua);
  132 
  133     /* Lua scripts can change our cwd and umask, save and restore */
  134     /* XXX TODO: use cwd from chroot state to save unnecessary open here */
  135     cwd = open(".", O_RDONLY);
  136     if (cwd != -1) {
  137     mode_t oldmask = umask(0);
  138     umask(oldmask);
  139     pid_t pid = getpid();
  140 
  141     if (chdir("/") == 0 && rpmluaRunScript(lua, script, sname) == 0) {
  142         rc = RPMRC_OK;
  143     }
  144     if (pid != getpid()) {
  145         /* Terminate child process forked in lua scriptlet */
  146         rpmlog(RPMLOG_ERR, _("No exec() called after fork() in lua scriptlet\n"));
  147         _exit(EXIT_FAILURE);
  148     }
  149     /* This failing would be fatal, return something different for it... */
  150     if (fchdir(cwd)) {
  151         rpmlog(RPMLOG_ERR, _("Unable to restore current directory: %m"));
  152         rc = RPMRC_NOTFOUND;
  153     }
  154     close(cwd);
  155     umask(oldmask);
  156     }
  157 
  158     rpmluaDelVar(lua, "arg");
  159     rpmluavFree(var);
  160 
  161 #else
  162     rpmlog(lvl, _("<lua> scriptlet support not built in\n"));
  163 #endif
  164 
  165     return rc;
  166 }
  167 
  168 static const char * const SCRIPT_PATH = "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin";
  169 
  170 static void doScriptExec(ARGV_const_t argv, ARGV_const_t prefixes,
  171             FD_t scriptFd, FD_t out)
  172 {
  173     int xx;
  174 
  175     /* SIGPIPE is ignored in rpm, reset to default for the scriptlet */
  176     (void) signal(SIGPIPE, SIG_DFL);
  177 
  178     rpmSetCloseOnExec();
  179 
  180     if (scriptFd != NULL) {
  181     int sfdno = Fileno(scriptFd);
  182     int ofdno = Fileno(out);
  183     if (sfdno != STDERR_FILENO)
  184         xx = dup2(sfdno, STDERR_FILENO);
  185     if (ofdno != STDOUT_FILENO)
  186         xx = dup2(ofdno, STDOUT_FILENO);
  187     /* make sure we don't close stdin/stderr/stdout by mistake! */
  188     if (ofdno > STDERR_FILENO && ofdno != sfdno)
  189         xx = Fclose (out);
  190     if (sfdno > STDERR_FILENO && ofdno != sfdno)
  191         xx = Fclose (scriptFd);
  192     }
  193 
  194     {   char *ipath = rpmExpand("%{_install_script_path}", NULL);
  195     const char *path = SCRIPT_PATH;
  196 
  197     if (ipath && ipath[5] != '%')
  198         path = ipath;
  199 
  200     xx = setenv("PATH", path, 1);
  201     free(ipath);
  202     }
  203 
  204     for (ARGV_const_t pf = prefixes; pf && *pf; pf++) {
  205     char *name = NULL;
  206     int num = (pf - prefixes);
  207 
  208     rasprintf(&name, "RPM_INSTALL_PREFIX%d", num);
  209     setenv(name, *pf, 1);
  210     free(name);
  211 
  212     /* scripts might still be using the old style prefix */
  213     if (num == 0) {
  214         setenv("RPM_INSTALL_PREFIX", *pf, 1);
  215     }
  216     }
  217     
  218     if (chdir("/") == 0) {
  219     /* XXX Don't mtrace into children. */
  220     unsetenv("MALLOC_CHECK_");
  221 
  222     xx = execv(argv[0], argv);
  223     if (xx) {
  224         rpmlog(RPMLOG_ERR,
  225             _("failed to exec scriptlet interpreter %s: %s\n"),
  226             argv[0], strerror(errno));
  227     }
  228     }
  229     _exit(127); /* exit 127 for compatibility with bash(1) */
  230 }
  231 
  232 static char * writeScript(const char *cmd, const char *script)
  233 {
  234     char *fn = NULL;
  235     size_t slen = strlen(script);
  236     int ok = 0;
  237     FD_t fd = rpmMkTempFile("/", &fn);
  238 
  239     if (Ferror(fd))
  240     goto exit;
  241 
  242     if (rpmIsDebug() && (rstreq(cmd, "/bin/sh") || rstreq(cmd, "/bin/bash"))) {
  243     static const char set_x[] = "set -x\n";
  244     /* Assume failures will be caught by the write below */
  245     Fwrite(set_x, sizeof(set_x[0]), sizeof(set_x)-1, fd);
  246     }
  247 
  248     ok = (Fwrite(script, sizeof(script[0]), slen, fd) == slen);
  249 
  250 exit:
  251     if (!ok) fn = _free(fn);
  252     Fclose(fd);
  253     return fn;
  254 }
  255 
  256 /**
  257  * Run an external script.
  258  */
  259 static rpmRC runExtScript(rpmPlugins plugins, ARGV_const_t prefixes,
  260            const char *sname, rpmlogLvl lvl, FD_t scriptFd,
  261            ARGV_t * argvp, const char *script, int arg1, int arg2,
  262            scriptNextFileFunc nextFileFunc)
  263 {
  264     FD_t out = NULL;
  265     char * fn = NULL;
  266     pid_t pid, reaped;
  267     int status;
  268     int inpipe[2];
  269     FILE *in = NULL;
  270     const char *line;
  271     char *mline = NULL;
  272     rpmRC rc = RPMRC_FAIL;
  273 
  274     rpmlog(RPMLOG_DEBUG, "%s: scriptlet start\n", sname);
  275 
  276     if (script) {
  277     fn = writeScript(*argvp[0], script);
  278     if (fn == NULL) {
  279         rpmlog(RPMLOG_ERR,
  280            _("Couldn't create temporary file for %s: %s\n"),
  281            sname, strerror(errno));
  282         goto exit;
  283     }
  284 
  285     argvAdd(argvp, fn);
  286     if (arg1 >= 0) {
  287         argvAddNum(argvp, arg1);
  288     }
  289     if (arg2 >= 0) {
  290         argvAddNum(argvp, arg2);
  291     }
  292     }
  293 
  294     if (pipe(inpipe) < 0) {
  295     rpmlog(RPMLOG_ERR,
  296         ("Couldn't create pipe: %s\n"), strerror(errno));
  297     goto exit;
  298     }
  299     in = fdopen(inpipe[1], "w");
  300     inpipe[1] = 0;
  301 
  302     if (scriptFd != NULL) {
  303     if (rpmIsVerbose()) {
  304         out = fdDup(Fileno(scriptFd));
  305     } else {
  306         out = Fopen("/dev/null", "w.fdio");
  307         if (Ferror(out)) {
  308         out = fdDup(Fileno(scriptFd));
  309         }
  310     }
  311     } else {
  312     out = fdDup(STDOUT_FILENO);
  313     }
  314     if (out == NULL) { 
  315     rpmlog(RPMLOG_ERR, _("Couldn't duplicate file descriptor: %s: %s\n"),
  316            sname, strerror(errno));
  317     goto exit;
  318     }
  319 
  320     pid = fork();
  321     if (pid == (pid_t) -1) {
  322     rpmlog(RPMLOG_ERR, _("Couldn't fork %s: %s\n"),
  323         sname, strerror(errno));
  324     goto exit;
  325     } else if (pid == 0) {/* Child */
  326     rpmlog(RPMLOG_DEBUG, "%s: execv(%s) pid %d\n",
  327            sname, *argvp[0], (unsigned)getpid());
  328 
  329     fclose(in);
  330     dup2(inpipe[0], STDIN_FILENO);
  331 
  332     /* Run scriptlet post fork hook for all plugins */
  333     if (rpmpluginsCallScriptletForkPost(plugins, *argvp[0], RPMSCRIPTLET_FORK | RPMSCRIPTLET_EXEC) != RPMRC_FAIL) {
  334         doScriptExec(*argvp, prefixes, scriptFd, out);
  335     } else {
  336         _exit(126); /* exit 126 for compatibility with bash(1) */
  337     }
  338     }
  339     close(inpipe[0]);
  340     inpipe[0] = 0;
  341 
  342     if (nextFileFunc->func) {
  343     while ((line = nextFileFunc->func(nextFileFunc->param)) != NULL) {
  344         size_t size = strlen(line);
  345         size_t ret_size;
  346         mline = xstrdup(line);
  347         mline[size] = '\n';
  348 
  349         ret_size = fwrite(mline, size + 1, 1, in);
  350         mline = _free(mline);
  351         if (ret_size != 1) {
  352         if (errno == EPIPE) {
  353             break;
  354         } else {
  355             rpmlog(RPMLOG_ERR, _("Fwrite failed: %s"), strerror(errno));
  356             rc = RPMRC_FAIL;
  357             goto exit;
  358         }
  359         }
  360     }
  361     }
  362     fclose(in);
  363     in = NULL;
  364 
  365     do {
  366     reaped = waitpid(pid, &status, 0);
  367     } while (reaped == -1 && errno == EINTR);
  368 
  369     rpmlog(RPMLOG_DEBUG, "%s: waitpid(%d) rc %d status %x\n",
  370        sname, (unsigned)pid, (unsigned)reaped, status);
  371 
  372     if (reaped < 0) {
  373     rpmlog(lvl, _("%s scriptlet failed, waitpid(%d) rc %d: %s\n"),
  374          sname, pid, reaped, strerror(errno));
  375     } else if (!WIFEXITED(status) || WEXITSTATUS(status)) {
  376         if (WIFSIGNALED(status)) {
  377         rpmlog(lvl, _("%s scriptlet failed, signal %d\n"),
  378                    sname, WTERMSIG(status));
  379     } else {
  380         rpmlog(lvl, _("%s scriptlet failed, exit status %d\n"),
  381            sname, WEXITSTATUS(status));
  382     }
  383     } else {
  384     /* if we get this far we're clear */
  385     rc = RPMRC_OK;
  386     }
  387 
  388 exit:
  389     if (in)
  390     fclose(in);
  391 
  392     if (inpipe[0])
  393     close(inpipe[0]);
  394 
  395     if (out)
  396     Fclose(out);    /* XXX dup'd STDOUT_FILENO */
  397 
  398     if (fn) {
  399     if (!rpmIsDebug())
  400         unlink(fn);
  401     free(fn);
  402     }
  403     free(mline);
  404 
  405     return rc;
  406 }
  407 
  408 rpmRC rpmScriptRun(rpmScript script, int arg1, int arg2, FD_t scriptFd,
  409            ARGV_const_t prefixes, rpmPlugins plugins)
  410 {
  411     if (script == NULL) return RPMRC_OK;
  412 
  413     ARGV_t args = NULL;
  414     rpmlogLvl lvl = (script->flags & RPMSCRIPT_FLAG_CRITICAL) ?
  415             RPMLOG_ERR : RPMLOG_WARNING;
  416     rpmRC rc;
  417     int script_type = RPMSCRIPTLET_FORK | RPMSCRIPTLET_EXEC;
  418 
  419     /* construct a new argv as we can't modify the one from header */
  420     if (script->args) {
  421     argvAppend(&args, script->args);
  422     } else {
  423     argvAdd(&args, "/bin/sh");
  424     }
  425     
  426     if (rstreq(args[0], "<lua>"))
  427     script_type = RPMSCRIPTLET_NONE;
  428 
  429     /* Run scriptlet pre hook for all plugins */
  430     rc = rpmpluginsCallScriptletPre(plugins, script->descr, script_type);
  431 
  432     if (rc != RPMRC_FAIL) {
  433     if (script_type & RPMSCRIPTLET_EXEC) {
  434         rc = runExtScript(plugins, prefixes, script->descr, lvl, scriptFd, &args, script->body, arg1, arg2, &script->nextFileFunc);
  435     } else {
  436         rc = runLuaScript(plugins, prefixes, script->descr, lvl, scriptFd, &args, script->body, arg1, arg2, &script->nextFileFunc);
  437     }
  438     }
  439 
  440     /* Run scriptlet post hook for all plugins */
  441     rpmpluginsCallScriptletPost(plugins, script->descr, script_type, rc);
  442 
  443     argvFree(args);
  444 
  445     return rc;
  446 }
  447 
  448 static rpmscriptTypes getScriptType(rpmTagVal scriptTag)
  449 {
  450     return findTag(scriptTag)->type;
  451 }
  452 
  453 static rpmTagVal getProgTag(rpmTagVal scriptTag)
  454 {
  455     return findTag(scriptTag)->progtag;
  456 }
  457 
  458 static rpmTagVal getFlagTag(rpmTagVal scriptTag)
  459 {
  460     return findTag(scriptTag)->flagtag;
  461 }
  462 
  463 static rpmscriptFlags getDefFlags(rpmTagVal scriptTag)
  464 {
  465     return findTag(scriptTag)->deflags;
  466 }
  467 
  468 static const char * tag2sln(rpmTagVal tag)
  469 {
  470     return findTag(tag)->desc;
  471 }
  472 
  473 static rpmScript rpmScriptNew(Header h, rpmTagVal tag, const char *body,
  474                   rpmscriptFlags flags)
  475 {
  476     char *nevra = headerGetAsString(h, RPMTAG_NEVRA);
  477     rpmScript script = xcalloc(1, sizeof(*script));
  478     script->tag = tag;
  479     script->type = getScriptType(tag);
  480     script->flags = getDefFlags(tag) | flags;
  481     script->body = (body != NULL) ? xstrdup(body) : NULL;
  482     rasprintf(&script->descr, "%s(%s)", tag2sln(tag), nevra);
  483 
  484     /* macros need to be expanded before possible queryformat */
  485     if (script->body && (script->flags & RPMSCRIPT_FLAG_EXPAND)) {
  486     char *body = rpmExpand(script->body, NULL);
  487     free(script->body);
  488     script->body = body;
  489     }
  490     if (script->body && (script->flags & RPMSCRIPT_FLAG_QFORMAT)) {
  491     /* XXX TODO: handle queryformat errors */
  492     char *body = headerFormat(h, script->body, NULL);
  493     free(script->body);
  494     script->body = body;
  495     }
  496 
  497     script->nextFileFunc.func = NULL;
  498     script->nextFileFunc.param = NULL;
  499 
  500     free(nevra);
  501     return script;
  502 }
  503 
  504 void rpmScriptSetNextFileFunc(rpmScript script, char *(*func)(void *),
  505                 void *param)
  506 {
  507     script->nextFileFunc.func = func;
  508     script->nextFileFunc.param = param;
  509 }
  510 
  511 rpmTagVal triggerDsTag(rpmscriptTriggerModes tm)
  512 {
  513     rpmTagVal tag = RPMTAG_NOT_FOUND;
  514     switch (tm) {
  515     case RPMSCRIPT_NORMALTRIGGER:
  516     tag = RPMTAG_TRIGGERNAME;
  517     break;
  518     case RPMSCRIPT_FILETRIGGER:
  519     tag = RPMTAG_FILETRIGGERNAME;
  520     break;
  521     case RPMSCRIPT_TRANSFILETRIGGER:
  522     tag = RPMTAG_TRANSFILETRIGGERNAME;
  523     break;
  524     }
  525     return tag;
  526 }
  527 
  528 rpmscriptTriggerModes triggerMode(rpmTagVal tag)
  529 {
  530     rpmscriptTriggerModes tm = 0;
  531     switch (tag) {
  532     case RPMTAG_TRIGGERNAME:
  533     tm = RPMSCRIPT_NORMALTRIGGER;
  534     break;
  535     case RPMTAG_FILETRIGGERNAME:
  536     tm = RPMSCRIPT_FILETRIGGER;
  537     break;
  538     case RPMTAG_TRANSFILETRIGGERNAME:
  539     tm = RPMSCRIPT_TRANSFILETRIGGER;
  540     break;
  541     }
  542     return tm;
  543 }
  544 
  545 rpmTagVal triggertag(rpmsenseFlags sense)
  546 {
  547     rpmTagVal tag = RPMTAG_NOT_FOUND;
  548     switch (sense) {
  549     case RPMSENSE_TRIGGERIN:
  550     tag = RPMTAG_TRIGGERIN;
  551     break;
  552     case RPMSENSE_TRIGGERUN:
  553     tag = RPMTAG_TRIGGERUN;
  554     break;
  555     case RPMSENSE_TRIGGERPOSTUN:
  556     tag = RPMTAG_TRIGGERPOSTUN;
  557     break;
  558     case RPMSENSE_TRIGGERPREIN:
  559     tag = RPMTAG_TRIGGERPREIN;
  560     break;
  561     default:
  562     break;
  563     }
  564     return tag;
  565 }
  566 
  567 rpmScript rpmScriptFromTriggerTag(Header h, rpmTagVal triggerTag,
  568                 rpmscriptTriggerModes tm, uint32_t ix)
  569 {
  570     rpmScript script = NULL;
  571     struct rpmtd_s tscripts, tprogs, tflags;
  572     headerGetFlags hgflags = HEADERGET_MINMEM;
  573 
  574     switch (tm) {
  575     case RPMSCRIPT_NORMALTRIGGER:
  576         headerGet(h, RPMTAG_TRIGGERSCRIPTS, &tscripts, hgflags);
  577         headerGet(h, RPMTAG_TRIGGERSCRIPTPROG, &tprogs, hgflags);
  578         headerGet(h, RPMTAG_TRIGGERSCRIPTFLAGS, &tflags, hgflags);
  579         break;
  580     case RPMSCRIPT_FILETRIGGER:
  581         headerGet(h, RPMTAG_FILETRIGGERSCRIPTS, &tscripts, hgflags);
  582         headerGet(h, RPMTAG_FILETRIGGERSCRIPTPROG, &tprogs, hgflags);
  583         headerGet(h, RPMTAG_FILETRIGGERSCRIPTFLAGS, &tflags, hgflags);
  584         break;
  585     case RPMSCRIPT_TRANSFILETRIGGER:
  586         headerGet(h, RPMTAG_TRANSFILETRIGGERSCRIPTS, &tscripts, hgflags);
  587         headerGet(h, RPMTAG_TRANSFILETRIGGERSCRIPTPROG, &tprogs, hgflags);
  588         headerGet(h, RPMTAG_TRANSFILETRIGGERSCRIPTFLAGS, &tflags, hgflags);
  589         break;
  590     }
  591 
  592     if (rpmtdSetIndex(&tscripts, ix) >= 0 && rpmtdSetIndex(&tprogs, ix) >= 0) {
  593     rpmscriptFlags sflags = 0;
  594     const char *prog = rpmtdGetString(&tprogs);
  595 
  596     if (rpmtdSetIndex(&tflags, ix) >= 0)
  597         sflags = rpmtdGetNumber(&tflags);
  598 
  599     script = rpmScriptNew(h, triggerTag, rpmtdGetString(&tscripts), sflags);
  600 
  601     /* hack up a hge-style NULL-terminated array */
  602     script->args = xmalloc(2 * sizeof(*script->args) + strlen(prog) + 1);
  603     script->args[0] = (char *)(script->args + 2);
  604     script->args[1] = NULL;
  605     strcpy(script->args[0], prog);
  606     }
  607 
  608     rpmtdFreeData(&tscripts);
  609     rpmtdFreeData(&tprogs);
  610     rpmtdFreeData(&tflags);
  611 
  612     return script;
  613 }
  614 
  615 rpmScript rpmScriptFromTag(Header h, rpmTagVal scriptTag)
  616 {
  617     rpmScript script = NULL;
  618     rpmTagVal progTag = getProgTag(scriptTag);
  619 
  620     if (headerIsEntry(h, scriptTag) || headerIsEntry(h, progTag)) {
  621     struct rpmtd_s prog;
  622 
  623     script = rpmScriptNew(h, scriptTag,
  624                   headerGetString(h, scriptTag),
  625                   headerGetNumber(h, getFlagTag(scriptTag)));
  626 
  627     if (headerGet(h, progTag, &prog, (HEADERGET_ALLOC|HEADERGET_ARGV))) {
  628         script->args = prog.data;
  629     }
  630     }
  631     return script;
  632 }
  633 
  634 rpmScript rpmScriptFree(rpmScript script)
  635 {
  636     if (script) {
  637     free(script->args);
  638     free(script->body);
  639     free(script->descr);
  640     free(script);
  641     }
  642     return NULL;
  643 }
  644 
  645 rpmTagVal rpmScriptTag(rpmScript script)
  646 {
  647     return (script != NULL) ? script->tag : RPMTAG_NOT_FOUND;
  648 }
  649 
  650 rpmscriptTypes rpmScriptType(rpmScript script)
  651 {
  652     return (script != NULL) ? script->type : 0;
  653 }
  654 
  655 rpmscriptFlags rpmScriptFlags(rpmScript script)
  656 {
  657     return (script != NULL) ? script->flags : 0;
  658 }