Add macro %isu_package to generate ISU Package
[platform/upstream/rpm.git] / build / parseScript.c
1 /** \ingroup rpmbuild
2  * \file build/parseScript.c
3  *  Parse install-time script section from spec file.
4  */
5
6 #include "system.h"
7
8 #include <rpm/header.h>
9 #include <rpm/rpmlog.h>
10
11 #include "rpmio/rpmlua.h"
12 #include "lib/rpmscript.h"      /* script flags */
13 #include "build/rpmbuild_internal.h"
14 #include "build/rpmbuild_misc.h"
15
16 #include "debug.h"
17
18
19 /**
20  */
21 static int addTriggerIndex(Package pkg, const char *file,
22         const char *script, const char *prog, rpmscriptFlags flags)
23 {
24     struct TriggerFileEntry *tfe;
25     struct TriggerFileEntry *list = pkg->triggerFiles;
26     struct TriggerFileEntry *last = NULL;
27     int index = 0;
28
29     while (list) {
30         last = list;
31         list = list->next;
32     }
33
34     if (last)
35         index = last->index + 1;
36
37     tfe = xcalloc(1, sizeof(*tfe));
38
39     tfe->fileName = (file) ? xstrdup(file) : NULL;
40     tfe->script = (script && *script != '\0') ? xstrdup(script) : NULL;
41     tfe->prog = xstrdup(prog);
42     tfe->flags = flags;
43     tfe->index = index;
44     tfe->next = NULL;
45
46     if (last)
47         last->next = tfe;
48     else
49         pkg->triggerFiles = tfe;
50
51     return index;
52 }
53
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.                                     */
58
59 int parseScript(rpmSpec spec, int parsePart)
60 {
61     /* There are a few options to scripts: */
62     /*  <pkg>                              */
63     /*  -n <pkg>                           */
64     /*  -p <sh>                            */
65     /*  -p "<sh> <args>..."                */
66     /*  -f <file>                          */
67
68     const char *p;
69     const char **progArgv = NULL;
70     int progArgc;
71     const char *partname = NULL;
72     rpmTagVal reqtag = 0;
73     rpmTagVal tag = 0;
74     rpmsenseFlags tagflags = 0;
75     rpmTagVal progtag = 0;
76     rpmTagVal flagtag = 0;
77     rpmscriptFlags scriptFlags = 0;
78     int flag = PART_SUBNAME;
79     Package pkg;
80     StringBuf sb = NULL;
81     int nextPart;
82     int index;
83     char * reqargs = NULL;
84
85     int res = PART_ERROR; /* assume failure */
86     int rc, argc;
87     int arg;
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,
98           NULL, NULL},
99         { NULL, 'q', POPT_BIT_SET, &scriptFlags, RPMSCRIPT_FLAG_QFORMAT,
100           NULL, NULL},
101         { 0, 0, 0, 0, 0,        NULL, NULL}
102     };
103
104     switch (parsePart) {
105       case PART_PRE:
106         tag = RPMTAG_PREIN;
107         tagflags = RPMSENSE_SCRIPT_PRE;
108         progtag = RPMTAG_PREINPROG;
109         flagtag = RPMTAG_PREINFLAGS;
110         partname = "%pre";
111         break;
112       case PART_POST:
113         tag = RPMTAG_POSTIN;
114         tagflags = RPMSENSE_SCRIPT_POST;
115         progtag = RPMTAG_POSTINPROG;
116         flagtag = RPMTAG_POSTINFLAGS;
117         partname = "%post";
118         break;
119       case PART_PREUN:
120         tag = RPMTAG_PREUN;
121         tagflags = RPMSENSE_SCRIPT_PREUN;
122         progtag = RPMTAG_PREUNPROG;
123         flagtag = RPMTAG_PREUNFLAGS;
124         partname = "%preun";
125         break;
126       case PART_POSTUN:
127         tag = RPMTAG_POSTUN;
128         tagflags = RPMSENSE_SCRIPT_POSTUN;
129         progtag = RPMTAG_POSTUNPROG;
130         flagtag = RPMTAG_POSTUNFLAGS;
131         partname = "%postun";
132         break;
133       case PART_PRETRANS:
134         tag = RPMTAG_PRETRANS;
135         tagflags = RPMSENSE_PRETRANS;
136         progtag = RPMTAG_PRETRANSPROG;
137         flagtag = RPMTAG_PRETRANSFLAGS;
138         partname = "%pretrans";
139         break;
140       case PART_POSTTRANS:
141         tag = RPMTAG_POSTTRANS;
142         tagflags = RPMSENSE_POSTTRANS;
143         progtag = RPMTAG_POSTTRANSPROG;
144         flagtag = RPMTAG_POSTTRANSFLAGS;
145         partname = "%posttrans";
146         break;
147       case PART_VERIFYSCRIPT:
148         tag = RPMTAG_VERIFYSCRIPT;
149         tagflags = RPMSENSE_SCRIPT_VERIFY;
150         progtag = RPMTAG_VERIFYSCRIPTPROG;
151         flagtag = RPMTAG_VERIFYSCRIPTFLAGS;
152         partname = "%verifyscript";
153         break;
154       case PART_TRIGGERPREIN:
155         tag = RPMTAG_TRIGGERSCRIPTS;
156         tagflags = 0;
157         reqtag = RPMTAG_TRIGGERPREIN;
158         progtag = RPMTAG_TRIGGERSCRIPTPROG;
159         flagtag = RPMTAG_TRIGGERSCRIPTFLAGS;
160         partname = "%triggerprein";
161         break;
162       case PART_TRIGGERIN:
163         tag = RPMTAG_TRIGGERSCRIPTS;
164         tagflags = 0;
165         reqtag = RPMTAG_TRIGGERIN;
166         progtag = RPMTAG_TRIGGERSCRIPTPROG;
167         flagtag = RPMTAG_TRIGGERSCRIPTFLAGS;
168         partname = "%triggerin";
169         break;
170       case PART_TRIGGERUN:
171         tag = RPMTAG_TRIGGERSCRIPTS;
172         tagflags = 0;
173         reqtag = RPMTAG_TRIGGERUN;
174         progtag = RPMTAG_TRIGGERSCRIPTPROG;
175         flagtag = RPMTAG_TRIGGERSCRIPTFLAGS;
176         partname = "%triggerun";
177         break;
178       case PART_TRIGGERPOSTUN:
179         tag = RPMTAG_TRIGGERSCRIPTS;
180         tagflags = 0;
181         reqtag = RPMTAG_TRIGGERPOSTUN;
182         progtag = RPMTAG_TRIGGERSCRIPTPROG;
183         flagtag = RPMTAG_TRIGGERSCRIPTFLAGS;
184         partname = "%triggerpostun";
185         break;
186     }
187
188     if (tag == RPMTAG_TRIGGERSCRIPTS) {
189         /* break line into two */
190         char *s = strstr(spec->line, "--");
191         if (!s) {
192             rpmlog(RPMLOG_ERR, _("line %d: triggers must have --: %s\n"),
193                      spec->lineNum, spec->line);
194             return PART_ERROR;
195         }
196
197         *s = '\0';
198         reqargs = xstrdup(s + 2);
199     }
200     
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));
204         goto exit;
205     }
206     
207     optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
208     while ((arg = poptGetNextOpt(optCon)) > 0) {
209         switch (arg) {
210         case 'p':
211             if (prog[0] == '<') {
212                 if (prog[strlen(prog)-1] != '>') {
213                     rpmlog(RPMLOG_ERR,
214                              _("line %d: internal script must end "
215                              "with \'>\': %s\n"), spec->lineNum, prog);
216                     goto exit;
217                 }
218             } else if (prog[0] != '/') {
219                 rpmlog(RPMLOG_ERR,
220                          _("line %d: script program must begin "
221                          "with \'/\': %s\n"), spec->lineNum, prog);
222                 goto exit;
223             }
224             break;
225         case 'n':
226             flag = PART_NAME;
227             break;
228         }
229     }
230     
231     if (arg < -1) {
232         rpmlog(RPMLOG_ERR, _("line %d: Bad option %s: %s\n"),
233                  spec->lineNum,
234                  poptBadOption(optCon, POPT_BADOPTION_NOALIAS), 
235                  spec->line);
236         goto exit;
237     }
238
239     if (poptPeekArg(optCon)) {
240         if (name == NULL)
241             name = poptGetArg(optCon);
242         if (poptPeekArg(optCon)) {
243             rpmlog(RPMLOG_ERR, _("line %d: Too many names: %s\n"),
244                      spec->lineNum,
245                      spec->line);
246             goto exit;
247         }
248     }
249     
250     if (lookupPackage(spec, name, flag, &pkg)) {
251         rpmlog(RPMLOG_ERR, _("line %d: Package does not exist: %s\n"),
252                  spec->lineNum, spec->line);
253         goto exit;
254     }
255
256     if (tag != RPMTAG_TRIGGERSCRIPTS) {
257         if (headerIsEntry(pkg->header, progtag)) {
258             rpmlog(RPMLOG_ERR, _("line %d: Second %s\n"),
259                      spec->lineNum, partname);
260             goto exit;
261         }
262     }
263
264     if ((rc = poptParseArgvString(prog, &progArgc, &progArgv))) {
265         rpmlog(RPMLOG_ERR, _("line %d: Error parsing %s: %s\n"),
266                  spec->lineNum, partname, poptStrerror(rc));
267         goto exit;
268     }
269
270     sb = newStringBuf();
271     if ((rc = readLine(spec, STRIP_NOTHING)) > 0) {
272         nextPart = PART_NONE;
273     } else if (rc < 0) {
274         goto exit;
275     } else {
276         while (! (nextPart = isPart(spec->line))) {
277             appendStringBuf(sb, spec->line);
278             if ((rc = readLine(spec, STRIP_NOTHING)) > 0) {
279                 nextPart = PART_NONE;
280                 break;
281             } else if (rc < 0) {
282                 goto exit;
283             }
284         }
285     }
286     stripTrailingBlanksStringBuf(sb);
287     p = getStringBuf(sb);
288
289 #ifdef WITH_LUA
290     if (rstreq(progArgv[0], "<lua>")) {
291         rpmlua lua = NULL; /* Global state. */
292         if (rpmluaCheckScript(lua, p, partname) != RPMRC_OK) {
293             goto exit;
294         }
295         (void) rpmlibNeedsFeature(pkg->header,
296                                   "BuiltinLuaScripts", "4.2.2-1");
297     } else
298 #endif
299     if (progArgv[0][0] == '<') {
300         rpmlog(RPMLOG_ERR,
301                  _("line %d: unsupported internal script: %s\n"),
302                  spec->lineNum, progArgv[0]);
303         goto exit;
304     } else {
305         (void) addReqProv(pkg->header, RPMTAG_REQUIRENAME,
306                 progArgv[0], NULL, (tagflags | RPMSENSE_INTERP), 0);
307     }
308
309     if (scriptFlags) {
310         rpmlibNeedsFeature(pkg->header, "ScriptletExpansion", "4.9.0-1");
311     }
312
313     /* Trigger script insertion is always delayed in order to */
314     /* get the index right.                                   */
315     if (tag == RPMTAG_TRIGGERSCRIPTS) {
316         if (progArgc > 1) {
317             rpmlog(RPMLOG_ERR,
318               _("line %d: interpreter arguments not allowed in triggers: %s\n"),
319               spec->lineNum, prog);
320             goto exit;
321         }
322         /* Add file/index/prog triple to the trigger file list */
323         index = addTriggerIndex(pkg, file, p, progArgv[0], scriptFlags);
324
325         /* Generate the trigger tags */
326         if (parseRCPOT(spec, pkg, reqargs, reqtag, index, tagflags))
327             goto exit;
328     } else {
329         struct rpmtd_s td;
330
331         /*
332          * XXX Ancient rpm uses STRING, not STRING_ARRAY type here. Construct
333          * the td manually and preserve legacy compat for now...
334          */
335         rpmtdReset(&td);
336         td.tag = progtag;
337         td.count = progArgc;
338         if (progArgc == 1) {
339             td.data = (void *) *progArgv;
340             td.type = RPM_STRING_TYPE;
341         } else {
342             (void) rpmlibNeedsFeature(pkg->header,
343                         "ScriptletInterpreterArgs", "4.0.3-1");
344             td.data = progArgv;
345             td.type = RPM_STRING_ARRAY_TYPE;
346         }
347         headerPut(pkg->header, &td, HEADERPUT_DEFAULT);
348
349         if (*p != '\0') {
350             headerPutString(pkg->header, tag, p);
351         }
352         if (scriptFlags) {
353             headerPutUint32(pkg->header, flagtag, &scriptFlags, 1);
354         }
355
356         if (file) {
357             switch (parsePart) {
358               case PART_PRE:
359                 pkg->preInFile = xstrdup(file);
360                 break;
361               case PART_POST:
362                 pkg->postInFile = xstrdup(file);
363                 break;
364               case PART_PREUN:
365                 pkg->preUnFile = xstrdup(file);
366                 break;
367               case PART_POSTUN:
368                 pkg->postUnFile = xstrdup(file);
369                 break;
370               case PART_PRETRANS:
371                 pkg->preTransFile = xstrdup(file);
372                 break;
373               case PART_POSTTRANS:
374                 pkg->postTransFile = xstrdup(file);
375                 break;
376               case PART_VERIFYSCRIPT:
377                 pkg->verifyFile = xstrdup(file);
378                 break;
379             }
380         }
381     }
382     res = nextPart;
383     
384 exit:
385     free(reqargs);
386     freeStringBuf(sb);
387     free(progArgv);
388     free(argv);
389     poptFreeContext(optCon);
390     
391     return res;
392 }