2 * \file build/parseScript.c
3 * Parse install-time script section from spec file.
8 #include <rpm/header.h>
9 #include <rpm/rpmlog.h>
11 #include "rpmio/rpmlua.h"
12 #include "lib/rpmscript.h" /* script flags */
13 #include "build/rpmbuild_internal.h"
14 #include "build/rpmbuild_misc.h"
21 static int addTriggerIndex(Package pkg, const char *file,
22 const char *script, const char *prog, rpmscriptFlags flags)
24 struct TriggerFileEntry *tfe;
25 struct TriggerFileEntry *list = pkg->triggerFiles;
26 struct TriggerFileEntry *last = NULL;
35 index = last->index + 1;
37 tfe = xcalloc(1, sizeof(*tfe));
39 tfe->fileName = (file) ? xstrdup(file) : NULL;
40 tfe->script = (script && *script != '\0') ? xstrdup(script) : NULL;
41 tfe->prog = xstrdup(prog);
49 pkg->triggerFiles = tfe;
54 /* %trigger is a strange combination of %pre and Requires: behavior */
55 /* We can handle it by parsing the args before "--" in parseScript. */
56 /* We then pass the remaining arguments to parseRCPOT, along with */
57 /* an index we just determined. */
59 int parseScript(rpmSpec spec, int parsePart)
61 /* There are a few options to scripts: */
65 /* -p "<sh> <args>..." */
69 const char **progArgv = NULL;
71 const char *partname = NULL;
74 rpmsenseFlags tagflags = 0;
75 rpmTagVal progtag = 0;
76 rpmTagVal flagtag = 0;
77 rpmscriptFlags scriptFlags = 0;
78 int flag = PART_SUBNAME;
83 char * reqargs = NULL;
85 int res = PART_ERROR; /* assume failure */
88 const char **argv = NULL;
89 poptContext optCon = NULL;
90 const char *name = NULL;
91 const char *prog = "/bin/sh";
92 const char *file = NULL;
93 struct poptOption optionsTable[] = {
94 { NULL, 'p', POPT_ARG_STRING, &prog, 'p', NULL, NULL},
95 { NULL, 'n', POPT_ARG_STRING, &name, 'n', NULL, NULL},
96 { NULL, 'f', POPT_ARG_STRING, &file, 'f', NULL, NULL},
97 { NULL, 'e', POPT_BIT_SET, &scriptFlags, RPMSCRIPT_FLAG_EXPAND,
99 { NULL, 'q', POPT_BIT_SET, &scriptFlags, RPMSCRIPT_FLAG_QFORMAT,
101 { 0, 0, 0, 0, 0, NULL, NULL}
107 tagflags = RPMSENSE_SCRIPT_PRE;
108 progtag = RPMTAG_PREINPROG;
109 flagtag = RPMTAG_PREINFLAGS;
114 tagflags = RPMSENSE_SCRIPT_POST;
115 progtag = RPMTAG_POSTINPROG;
116 flagtag = RPMTAG_POSTINFLAGS;
121 tagflags = RPMSENSE_SCRIPT_PREUN;
122 progtag = RPMTAG_PREUNPROG;
123 flagtag = RPMTAG_PREUNFLAGS;
128 tagflags = RPMSENSE_SCRIPT_POSTUN;
129 progtag = RPMTAG_POSTUNPROG;
130 flagtag = RPMTAG_POSTUNFLAGS;
131 partname = "%postun";
134 tag = RPMTAG_PRETRANS;
135 tagflags = RPMSENSE_PRETRANS;
136 progtag = RPMTAG_PRETRANSPROG;
137 flagtag = RPMTAG_PRETRANSFLAGS;
138 partname = "%pretrans";
141 tag = RPMTAG_POSTTRANS;
142 tagflags = RPMSENSE_POSTTRANS;
143 progtag = RPMTAG_POSTTRANSPROG;
144 flagtag = RPMTAG_POSTTRANSFLAGS;
145 partname = "%posttrans";
147 case PART_VERIFYSCRIPT:
148 tag = RPMTAG_VERIFYSCRIPT;
149 tagflags = RPMSENSE_SCRIPT_VERIFY;
150 progtag = RPMTAG_VERIFYSCRIPTPROG;
151 flagtag = RPMTAG_VERIFYSCRIPTFLAGS;
152 partname = "%verifyscript";
154 case PART_TRIGGERPREIN:
155 tag = RPMTAG_TRIGGERSCRIPTS;
157 reqtag = RPMTAG_TRIGGERPREIN;
158 progtag = RPMTAG_TRIGGERSCRIPTPROG;
159 flagtag = RPMTAG_TRIGGERSCRIPTFLAGS;
160 partname = "%triggerprein";
163 tag = RPMTAG_TRIGGERSCRIPTS;
165 reqtag = RPMTAG_TRIGGERIN;
166 progtag = RPMTAG_TRIGGERSCRIPTPROG;
167 flagtag = RPMTAG_TRIGGERSCRIPTFLAGS;
168 partname = "%triggerin";
171 tag = RPMTAG_TRIGGERSCRIPTS;
173 reqtag = RPMTAG_TRIGGERUN;
174 progtag = RPMTAG_TRIGGERSCRIPTPROG;
175 flagtag = RPMTAG_TRIGGERSCRIPTFLAGS;
176 partname = "%triggerun";
178 case PART_TRIGGERPOSTUN:
179 tag = RPMTAG_TRIGGERSCRIPTS;
181 reqtag = RPMTAG_TRIGGERPOSTUN;
182 progtag = RPMTAG_TRIGGERSCRIPTPROG;
183 flagtag = RPMTAG_TRIGGERSCRIPTFLAGS;
184 partname = "%triggerpostun";
188 if (tag == RPMTAG_TRIGGERSCRIPTS) {
189 /* break line into two */
190 char *s = strstr(spec->line, "--");
192 rpmlog(RPMLOG_ERR, _("line %d: triggers must have --: %s\n"),
193 spec->lineNum, spec->line);
198 reqargs = xstrdup(s + 2);
201 if ((rc = poptParseArgvString(spec->line, &argc, &argv))) {
202 rpmlog(RPMLOG_ERR, _("line %d: Error parsing %s: %s\n"),
203 spec->lineNum, partname, poptStrerror(rc));
207 optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
208 while ((arg = poptGetNextOpt(optCon)) > 0) {
211 if (prog[0] == '<') {
212 if (prog[strlen(prog)-1] != '>') {
214 _("line %d: internal script must end "
215 "with \'>\': %s\n"), spec->lineNum, prog);
218 } else if (prog[0] != '/') {
220 _("line %d: script program must begin "
221 "with \'/\': %s\n"), spec->lineNum, prog);
232 rpmlog(RPMLOG_ERR, _("line %d: Bad option %s: %s\n"),
234 poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
239 if (poptPeekArg(optCon)) {
241 name = poptGetArg(optCon);
242 if (poptPeekArg(optCon)) {
243 rpmlog(RPMLOG_ERR, _("line %d: Too many names: %s\n"),
250 if (lookupPackage(spec, name, flag, &pkg)) {
251 rpmlog(RPMLOG_ERR, _("line %d: Package does not exist: %s\n"),
252 spec->lineNum, spec->line);
256 if (tag != RPMTAG_TRIGGERSCRIPTS) {
257 if (headerIsEntry(pkg->header, progtag)) {
258 rpmlog(RPMLOG_ERR, _("line %d: Second %s\n"),
259 spec->lineNum, partname);
264 if ((rc = poptParseArgvString(prog, &progArgc, &progArgv))) {
265 rpmlog(RPMLOG_ERR, _("line %d: Error parsing %s: %s\n"),
266 spec->lineNum, partname, poptStrerror(rc));
271 if ((rc = readLine(spec, STRIP_NOTHING)) > 0) {
272 nextPart = PART_NONE;
276 while (! (nextPart = isPart(spec->line))) {
277 appendStringBuf(sb, spec->line);
278 if ((rc = readLine(spec, STRIP_NOTHING)) > 0) {
279 nextPart = PART_NONE;
286 stripTrailingBlanksStringBuf(sb);
287 p = getStringBuf(sb);
290 if (rstreq(progArgv[0], "<lua>")) {
291 rpmlua lua = NULL; /* Global state. */
292 if (rpmluaCheckScript(lua, p, partname) != RPMRC_OK) {
295 (void) rpmlibNeedsFeature(pkg->header,
296 "BuiltinLuaScripts", "4.2.2-1");
299 if (progArgv[0][0] == '<') {
301 _("line %d: unsupported internal script: %s\n"),
302 spec->lineNum, progArgv[0]);
305 (void) addReqProv(pkg->header, RPMTAG_REQUIRENAME,
306 progArgv[0], NULL, (tagflags | RPMSENSE_INTERP), 0);
310 rpmlibNeedsFeature(pkg->header, "ScriptletExpansion", "4.9.0-1");
313 /* Trigger script insertion is always delayed in order to */
314 /* get the index right. */
315 if (tag == RPMTAG_TRIGGERSCRIPTS) {
318 _("line %d: interpreter arguments not allowed in triggers: %s\n"),
319 spec->lineNum, prog);
322 /* Add file/index/prog triple to the trigger file list */
323 index = addTriggerIndex(pkg, file, p, progArgv[0], scriptFlags);
325 /* Generate the trigger tags */
326 if (parseRCPOT(spec, pkg, reqargs, reqtag, index, tagflags))
332 * XXX Ancient rpm uses STRING, not STRING_ARRAY type here. Construct
333 * the td manually and preserve legacy compat for now...
339 td.data = (void *) *progArgv;
340 td.type = RPM_STRING_TYPE;
342 (void) rpmlibNeedsFeature(pkg->header,
343 "ScriptletInterpreterArgs", "4.0.3-1");
345 td.type = RPM_STRING_ARRAY_TYPE;
347 headerPut(pkg->header, &td, HEADERPUT_DEFAULT);
350 headerPutString(pkg->header, tag, p);
353 headerPutUint32(pkg->header, flagtag, &scriptFlags, 1);
359 pkg->preInFile = xstrdup(file);
362 pkg->postInFile = xstrdup(file);
365 pkg->preUnFile = xstrdup(file);
368 pkg->postUnFile = xstrdup(file);
371 pkg->preTransFile = xstrdup(file);
374 pkg->postTransFile = xstrdup(file);
376 case PART_VERIFYSCRIPT:
377 pkg->verifyFile = xstrdup(file);
389 poptFreeContext(optCon);