summaryrefslogtreecommitdiff
path: root/build/parseScript.c
diff options
context:
space:
mode:
Diffstat (limited to 'build/parseScript.c')
-rw-r--r--build/parseScript.c389
1 files changed, 389 insertions, 0 deletions
diff --git a/build/parseScript.c b/build/parseScript.c
new file mode 100644
index 0000000..87b3d58
--- /dev/null
+++ b/build/parseScript.c
@@ -0,0 +1,389 @@
+/** \ingroup rpmbuild
+ * \file build/parseScript.c
+ * Parse install-time script section from spec file.
+ */
+
+#include "system.h"
+
+#include <rpm/header.h>
+#include <rpm/rpmlog.h>
+
+#include "rpmio/rpmlua.h"
+#include "lib/rpmscript.h" /* script flags */
+#include "build/rpmbuild_internal.h"
+#include "build/rpmbuild_misc.h"
+
+#include "debug.h"
+
+
+/**
+ */
+static int addTriggerIndex(Package pkg, const char *file,
+ const char *script, const char *prog, rpmscriptFlags flags)
+{
+ struct TriggerFileEntry *tfe;
+ struct TriggerFileEntry *list = pkg->triggerFiles;
+ struct TriggerFileEntry *last = NULL;
+ int index = 0;
+
+ while (list) {
+ last = list;
+ list = list->next;
+ }
+
+ if (last)
+ index = last->index + 1;
+
+ tfe = xcalloc(1, sizeof(*tfe));
+
+ tfe->fileName = (file) ? xstrdup(file) : NULL;
+ tfe->script = (script && *script != '\0') ? xstrdup(script) : NULL;
+ tfe->prog = xstrdup(prog);
+ tfe->flags = flags;
+ tfe->index = index;
+ tfe->next = NULL;
+
+ if (last)
+ last->next = tfe;
+ else
+ pkg->triggerFiles = tfe;
+
+ return index;
+}
+
+/* %trigger is a strange combination of %pre and Requires: behavior */
+/* We can handle it by parsing the args before "--" in parseScript. */
+/* We then pass the remaining arguments to parseRCPOT, along with */
+/* an index we just determined. */
+
+int parseScript(rpmSpec spec, int parsePart)
+{
+ /* There are a few options to scripts: */
+ /* <pkg> */
+ /* -n <pkg> */
+ /* -p <sh> */
+ /* -p "<sh> <args>..." */
+ /* -f <file> */
+
+ const char *p;
+ const char **progArgv = NULL;
+ int progArgc;
+ const char *partname = NULL;
+ rpmTagVal reqtag = 0;
+ rpmTagVal tag = 0;
+ rpmsenseFlags tagflags = 0;
+ rpmTagVal progtag = 0;
+ rpmTagVal flagtag = 0;
+ rpmscriptFlags scriptFlags = 0;
+ int flag = PART_SUBNAME;
+ Package pkg;
+ StringBuf sb = NULL;
+ int nextPart;
+ int index;
+ char * reqargs = NULL;
+
+ int res = PART_ERROR; /* assume failure */
+ int rc, argc;
+ int arg;
+ const char **argv = NULL;
+ poptContext optCon = NULL;
+ const char *name = NULL;
+ const char *prog = "/bin/sh";
+ const char *file = NULL;
+ int expand = 0;
+ int qformat = 0;
+ struct poptOption optionsTable[] = {
+ { NULL, 'p', POPT_ARG_STRING, &prog, 'p', NULL, NULL},
+ { NULL, 'n', POPT_ARG_STRING, &name, 'n', NULL, NULL},
+ { NULL, 'f', POPT_ARG_STRING, &file, 'f', NULL, NULL},
+ { NULL, 'e', POPT_ARG_NONE, &expand, 'e', NULL, NULL},
+ { NULL, 'q', POPT_ARG_NONE, &qformat, 'q', NULL, NULL},
+ { 0, 0, 0, 0, 0, NULL, NULL}
+ };
+
+ switch (parsePart) {
+ case PART_PRE:
+ tag = RPMTAG_PREIN;
+ tagflags = RPMSENSE_SCRIPT_PRE;
+ progtag = RPMTAG_PREINPROG;
+ flagtag = RPMTAG_PREINFLAGS;
+ partname = "%pre";
+ break;
+ case PART_POST:
+ tag = RPMTAG_POSTIN;
+ tagflags = RPMSENSE_SCRIPT_POST;
+ progtag = RPMTAG_POSTINPROG;
+ flagtag = RPMTAG_POSTINFLAGS;
+ partname = "%post";
+ break;
+ case PART_PREUN:
+ tag = RPMTAG_PREUN;
+ tagflags = RPMSENSE_SCRIPT_PREUN;
+ progtag = RPMTAG_PREUNPROG;
+ flagtag = RPMTAG_PREUNFLAGS;
+ partname = "%preun";
+ break;
+ case PART_POSTUN:
+ tag = RPMTAG_POSTUN;
+ tagflags = RPMSENSE_SCRIPT_POSTUN;
+ progtag = RPMTAG_POSTUNPROG;
+ flagtag = RPMTAG_POSTUNFLAGS;
+ partname = "%postun";
+ break;
+ case PART_PRETRANS:
+ tag = RPMTAG_PRETRANS;
+ tagflags = RPMSENSE_PRETRANS;
+ progtag = RPMTAG_PRETRANSPROG;
+ flagtag = RPMTAG_PRETRANSFLAGS;
+ partname = "%pretrans";
+ break;
+ case PART_POSTTRANS:
+ tag = RPMTAG_POSTTRANS;
+ tagflags = RPMSENSE_POSTTRANS;
+ progtag = RPMTAG_POSTTRANSPROG;
+ flagtag = RPMTAG_POSTTRANSFLAGS;
+ partname = "%posttrans";
+ break;
+ case PART_VERIFYSCRIPT:
+ tag = RPMTAG_VERIFYSCRIPT;
+ tagflags = RPMSENSE_SCRIPT_VERIFY;
+ progtag = RPMTAG_VERIFYSCRIPTPROG;
+ flagtag = RPMTAG_VERIFYSCRIPTFLAGS;
+ partname = "%verifyscript";
+ break;
+ case PART_TRIGGERPREIN:
+ tag = RPMTAG_TRIGGERSCRIPTS;
+ tagflags = 0;
+ reqtag = RPMTAG_TRIGGERPREIN;
+ progtag = RPMTAG_TRIGGERSCRIPTPROG;
+ flagtag = RPMTAG_TRIGGERSCRIPTFLAGS;
+ partname = "%triggerprein";
+ break;
+ case PART_TRIGGERIN:
+ tag = RPMTAG_TRIGGERSCRIPTS;
+ tagflags = 0;
+ reqtag = RPMTAG_TRIGGERIN;
+ progtag = RPMTAG_TRIGGERSCRIPTPROG;
+ flagtag = RPMTAG_TRIGGERSCRIPTFLAGS;
+ partname = "%triggerin";
+ break;
+ case PART_TRIGGERUN:
+ tag = RPMTAG_TRIGGERSCRIPTS;
+ tagflags = 0;
+ reqtag = RPMTAG_TRIGGERUN;
+ progtag = RPMTAG_TRIGGERSCRIPTPROG;
+ flagtag = RPMTAG_TRIGGERSCRIPTFLAGS;
+ partname = "%triggerun";
+ break;
+ case PART_TRIGGERPOSTUN:
+ tag = RPMTAG_TRIGGERSCRIPTS;
+ tagflags = 0;
+ reqtag = RPMTAG_TRIGGERPOSTUN;
+ progtag = RPMTAG_TRIGGERSCRIPTPROG;
+ flagtag = RPMTAG_TRIGGERSCRIPTFLAGS;
+ partname = "%triggerpostun";
+ break;
+ }
+
+ if (tag == RPMTAG_TRIGGERSCRIPTS) {
+ /* break line into two */
+ char *s = strstr(spec->line, "--");
+ if (!s) {
+ rpmlog(RPMLOG_ERR, _("line %d: triggers must have --: %s\n"),
+ spec->lineNum, spec->line);
+ return PART_ERROR;
+ }
+
+ *s = '\0';
+ reqargs = xstrdup(s + 2);
+ }
+
+ if ((rc = poptParseArgvString(spec->line, &argc, &argv))) {
+ rpmlog(RPMLOG_ERR, _("line %d: Error parsing %s: %s\n"),
+ spec->lineNum, partname, poptStrerror(rc));
+ goto exit;
+ }
+
+ optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
+ while ((arg = poptGetNextOpt(optCon)) > 0) {
+ switch (arg) {
+ case 'p':
+ if (prog[0] == '<') {
+ if (prog[strlen(prog)-1] != '>') {
+ rpmlog(RPMLOG_ERR,
+ _("line %d: internal script must end "
+ "with \'>\': %s\n"), spec->lineNum, prog);
+ goto exit;
+ }
+ } else if (prog[0] != '/') {
+ rpmlog(RPMLOG_ERR,
+ _("line %d: script program must begin "
+ "with \'/\': %s\n"), spec->lineNum, prog);
+ goto exit;
+ }
+ break;
+ case 'n':
+ flag = PART_NAME;
+ break;
+ }
+ }
+
+ if (arg < -1) {
+ rpmlog(RPMLOG_ERR, _("line %d: Bad option %s: %s\n"),
+ spec->lineNum,
+ poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
+ spec->line);
+ goto exit;
+ }
+
+ if (poptPeekArg(optCon)) {
+ if (name == NULL)
+ name = poptGetArg(optCon);
+ if (poptPeekArg(optCon)) {
+ rpmlog(RPMLOG_ERR, _("line %d: Too many names: %s\n"),
+ spec->lineNum,
+ spec->line);
+ goto exit;
+ }
+ }
+
+ if (lookupPackage(spec, name, flag, &pkg)) {
+ rpmlog(RPMLOG_ERR, _("line %d: Package does not exist: %s\n"),
+ spec->lineNum, spec->line);
+ goto exit;
+ }
+
+ if (tag != RPMTAG_TRIGGERSCRIPTS) {
+ if (headerIsEntry(pkg->header, progtag)) {
+ rpmlog(RPMLOG_ERR, _("line %d: Second %s\n"),
+ spec->lineNum, partname);
+ goto exit;
+ }
+ }
+
+ if ((rc = poptParseArgvString(prog, &progArgc, &progArgv))) {
+ rpmlog(RPMLOG_ERR, _("line %d: Error parsing %s: %s\n"),
+ spec->lineNum, partname, poptStrerror(rc));
+ goto exit;
+ }
+
+ scriptFlags |= expand ? RPMSCRIPT_EXPAND : 0;
+ scriptFlags |= qformat ? RPMSCRIPT_QFORMAT : 0;
+
+ sb = newStringBuf();
+ if ((rc = readLine(spec, STRIP_NOTHING)) > 0) {
+ nextPart = PART_NONE;
+ } else if (rc < 0) {
+ goto exit;
+ } else {
+ while (! (nextPart = isPart(spec->line))) {
+ appendStringBuf(sb, spec->line);
+ if ((rc = readLine(spec, STRIP_NOTHING)) > 0) {
+ nextPart = PART_NONE;
+ break;
+ } else if (rc < 0) {
+ goto exit;
+ }
+ }
+ }
+ stripTrailingBlanksStringBuf(sb);
+ p = getStringBuf(sb);
+
+#ifdef WITH_LUA
+ if (rstreq(progArgv[0], "<lua>")) {
+ rpmlua lua = NULL; /* Global state. */
+ if (rpmluaCheckScript(lua, p, partname) != RPMRC_OK) {
+ goto exit;
+ }
+ (void) rpmlibNeedsFeature(pkg->header,
+ "BuiltinLuaScripts", "4.2.2-1");
+ } else
+#endif
+ if (progArgv[0][0] == '<') {
+ rpmlog(RPMLOG_ERR,
+ _("line %d: unsupported internal script: %s\n"),
+ spec->lineNum, progArgv[0]);
+ goto exit;
+ } else {
+ (void) addReqProv(pkg->header, RPMTAG_REQUIRENAME,
+ progArgv[0], NULL, (tagflags | RPMSENSE_INTERP), 0);
+ }
+
+ if (scriptFlags) {
+ rpmlibNeedsFeature(pkg->header, "ScriptletExpansion", "4.9.0-1");
+ }
+
+ /* Trigger script insertion is always delayed in order to */
+ /* get the index right. */
+ if (tag == RPMTAG_TRIGGERSCRIPTS) {
+ /* Add file/index/prog triple to the trigger file list */
+ index = addTriggerIndex(pkg, file, p, progArgv[0], scriptFlags);
+
+ /* Generate the trigger tags */
+ if ((rc = parseRCPOT(spec, pkg, reqargs, reqtag, index, tagflags)))
+ goto exit;
+ } else {
+ struct rpmtd_s td;
+
+ /*
+ * XXX Ancient rpm uses STRING, not STRING_ARRAY type here. Construct
+ * the td manually and preserve legacy compat for now...
+ */
+ rpmtdReset(&td);
+ td.tag = progtag;
+ td.count = progArgc;
+ if (progArgc == 1) {
+ td.data = (void *) *progArgv;
+ td.type = RPM_STRING_TYPE;
+ } else {
+ (void) rpmlibNeedsFeature(pkg->header,
+ "ScriptletInterpreterArgs", "4.0.3-1");
+ td.data = progArgv;
+ td.type = RPM_STRING_ARRAY_TYPE;
+ }
+ headerPut(pkg->header, &td, HEADERPUT_DEFAULT);
+
+ if (*p != '\0') {
+ headerPutString(pkg->header, tag, p);
+ }
+ if (scriptFlags) {
+ headerPutUint32(pkg->header, flagtag, &scriptFlags, 1);
+ }
+
+ if (file) {
+ switch (parsePart) {
+ case PART_PRE:
+ pkg->preInFile = xstrdup(file);
+ break;
+ case PART_POST:
+ pkg->postInFile = xstrdup(file);
+ break;
+ case PART_PREUN:
+ pkg->preUnFile = xstrdup(file);
+ break;
+ case PART_POSTUN:
+ pkg->postUnFile = xstrdup(file);
+ break;
+ case PART_PRETRANS:
+ pkg->preTransFile = xstrdup(file);
+ break;
+ case PART_POSTTRANS:
+ pkg->postTransFile = xstrdup(file);
+ break;
+ case PART_VERIFYSCRIPT:
+ pkg->verifyFile = xstrdup(file);
+ break;
+ }
+ }
+ }
+ res = nextPart;
+
+exit:
+ free(reqargs);
+ sb = freeStringBuf(sb);
+ progArgv = _free(progArgv);
+ argv = _free(argv);
+ optCon = poptFreeContext(optCon);
+
+ return res;
+}