Start experimental support for bzip2 payloads.
[platform/upstream/rpm.git] / build / parseScript.c
1 #include "system.h"
2
3 #include "rpmbuild.h"
4
5 static int addTriggerIndex(Package pkg, char *file, char *script, char *prog)
6 {
7     struct TriggerFileEntry *new;
8     struct TriggerFileEntry *list = pkg->triggerFiles;
9     struct TriggerFileEntry *last = NULL;
10     int index = 0;
11
12     while (list) {
13         last = list;
14         list = list->next;
15     }
16
17     if (last) {
18         index = last->index + 1;
19     }
20
21     new = malloc(sizeof(*new));
22
23     new->fileName = (file) ? strdup(file) : NULL;
24     new->script = (*script) ? strdup(script) : NULL;
25     new->prog = strdup(prog);
26     new->index = index;
27     new->next = NULL;
28
29     if (last) {
30         last->next = new;
31     } else {
32         pkg->triggerFiles = new;
33     }
34
35     return index;
36 }
37
38 /* these have to be global because of stupid compilers */
39     static char *name;
40     static char *prog;
41     static char *file;
42     static struct poptOption optionsTable[] = {
43         { NULL, 'p', POPT_ARG_STRING, &prog, 'p',       NULL, NULL},
44         { NULL, 'n', POPT_ARG_STRING, &name, 'n',       NULL, NULL},
45         { NULL, 'f', POPT_ARG_STRING, &file, 'f',       NULL, NULL},
46         { 0, 0, 0, 0, 0,        NULL, NULL}
47     };
48
49 /* %trigger is a strange combination of %pre and Requires: behavior */
50 /* We can handle it by parsing the args before "--" in parseScript. */
51 /* We then pass the remaining arguments to parseRCPOT, along with   */
52 /* an index we just determined.                                     */
53
54 int parseScript(Spec spec, int parsePart)
55 {
56     /* There are a few options to scripts: */
57     /*  <pkg>                              */
58     /*  -n <pkg>                           */
59     /*  -p <sh>                            */
60     /*  -p "<sh> <args>..."                */
61     /*  -f <file>                          */
62
63     char *p;
64     char **progArgv = NULL;
65     int progArgc;
66     char *partname = NULL;
67     int reqtag = 0;
68     int tag = 0;
69     int progtag = 0;
70     int flag = PART_SUBNAME;
71     Package pkg;
72     StringBuf sb;
73     int nextPart;
74     int index;
75     char reqargs[BUFSIZ];
76
77     int rc, argc;
78     int arg;
79     char **argv = NULL;
80     poptContext optCon = NULL;
81     
82     name = NULL;
83     prog = "/bin/sh";
84     file = NULL;
85     
86     switch (parsePart) {
87       case PART_PRE:
88         tag = RPMTAG_PREIN;
89         progtag = RPMTAG_PREINPROG;
90         partname = "%pre";
91         break;
92       case PART_POST:
93         tag = RPMTAG_POSTIN;
94         progtag = RPMTAG_POSTINPROG;
95         partname = "%post";
96         break;
97       case PART_PREUN:
98         tag = RPMTAG_PREUN;
99         progtag = RPMTAG_PREUNPROG;
100         partname = "%preun";
101         break;
102       case PART_POSTUN:
103         tag = RPMTAG_POSTUN;
104         progtag = RPMTAG_POSTUNPROG;
105         partname = "%postun";
106         break;
107       case PART_VERIFYSCRIPT:
108         tag = RPMTAG_VERIFYSCRIPT;
109         progtag = RPMTAG_VERIFYSCRIPTPROG;
110         partname = "%verifyscript";
111         break;
112       case PART_TRIGGERIN:
113         tag = RPMTAG_TRIGGERSCRIPTS;
114         reqtag = RPMTAG_TRIGGERIN;
115         progtag = RPMTAG_TRIGGERSCRIPTPROG;
116         partname = "%triggerin";
117         break;
118       case PART_TRIGGERUN:
119         tag = RPMTAG_TRIGGERSCRIPTS;
120         reqtag = RPMTAG_TRIGGERUN;
121         progtag = RPMTAG_TRIGGERSCRIPTPROG;
122         partname = "%triggerun";
123         break;
124       case PART_TRIGGERPOSTUN:
125         tag = RPMTAG_TRIGGERSCRIPTS;
126         reqtag = RPMTAG_TRIGGERPOSTUN;
127         progtag = RPMTAG_TRIGGERSCRIPTPROG;
128         partname = "%triggerpostun";
129         break;
130     }
131
132     if (tag == RPMTAG_TRIGGERSCRIPTS) {
133         /* break line into two */
134         p = strstr(spec->line, "--");
135         if (!p) {
136             rpmError(RPMERR_BADSPEC, _("line %d: triggers must have --: %s"),
137                      spec->lineNum, spec->line);
138             return RPMERR_BADSPEC;
139         }
140
141         *p = '\0';
142         strcpy(reqargs, p + 2);
143     }
144     
145     if ((rc = poptParseArgvString(spec->line, &argc, &argv))) {
146         rpmError(RPMERR_BADSPEC, _("line %d: Error parsing %s: %s"),
147                  spec->lineNum, partname, poptStrerror(rc));
148         return RPMERR_BADSPEC;
149     }
150     
151     optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
152     while ((arg = poptGetNextOpt(optCon)) > 0) {
153         if (arg == 'p') {
154             if (prog[0] != '/') {
155                 rpmError(RPMERR_BADSPEC,
156                          _("line %d: script program must begin "
157                          "with \'/\': %s"), spec->lineNum, prog);
158                 FREE(argv);
159                 poptFreeContext(optCon);
160                 return RPMERR_BADSPEC;
161             }
162         } else if (arg == 'n') {
163             flag = PART_NAME;
164         }
165     }
166     
167     if (arg < -1) {
168         rpmError(RPMERR_BADSPEC, _("line %d: Bad option %s: %s"),
169                  spec->lineNum,
170                  poptBadOption(optCon, POPT_BADOPTION_NOALIAS), 
171                  spec->line);
172         FREE(argv);
173         poptFreeContext(optCon);
174         return RPMERR_BADSPEC;
175     }
176
177     if (poptPeekArg(optCon)) {
178         if (! name) {
179             name = poptGetArg(optCon);
180         }
181         if (poptPeekArg(optCon)) {
182             rpmError(RPMERR_BADSPEC, _("line %d: Too many names: %s"),
183                      spec->lineNum,
184                      spec->line);
185             FREE(argv);
186             poptFreeContext(optCon);
187             return RPMERR_BADSPEC;
188         }
189     }
190     
191     if (lookupPackage(spec, name, flag, &pkg)) {
192         rpmError(RPMERR_BADSPEC, _("line %d: Package does not exist: %s"),
193                  spec->lineNum, spec->line);
194         FREE(argv);
195         poptFreeContext(optCon);
196         return RPMERR_BADSPEC;
197     }
198
199     if (tag != RPMTAG_TRIGGERSCRIPTS) {
200         if (headerIsEntry(pkg->header, progtag)) {
201             rpmError(RPMERR_BADSPEC, _("line %d: Second %s"),
202                      spec->lineNum, partname);
203             FREE(argv);
204             poptFreeContext(optCon);
205             return RPMERR_BADSPEC;
206         }
207     }
208
209     if ((rc = poptParseArgvString(prog, &progArgc, &progArgv))) {
210         rpmError(RPMERR_BADSPEC, _("line %d: Error parsing %s: %s"),
211                  spec->lineNum, partname, poptStrerror(rc));
212         FREE(argv);
213         poptFreeContext(optCon);
214         return RPMERR_BADSPEC;
215     }
216     
217     sb = newStringBuf();
218     if ((rc = readLine(spec, STRIP_NOTHING)) > 0) {
219         nextPart = PART_NONE;
220     } else {
221         if (rc) {
222             return rc;
223         }
224         while (! (nextPart = isPart(spec->line))) {
225             appendStringBuf(sb, spec->line);
226             if ((rc = readLine(spec, STRIP_NOTHING)) > 0) {
227                 nextPart = PART_NONE;
228                 break;
229             }
230             if (rc) {
231                 return rc;
232             }
233         }
234     }
235     stripTrailingBlanksStringBuf(sb);
236     p = getStringBuf(sb);
237
238     addReqProv(spec, pkg->header, RPMSENSE_PREREQ, prog, NULL, 0);
239
240     /* Trigger script insertion is always delayed in order to */
241     /* get the index right.                                   */
242     if (tag == RPMTAG_TRIGGERSCRIPTS) {
243         /* Add file/index/prog triple to the trigger file list */
244         index = addTriggerIndex(pkg, file, p, prog);
245
246         /* Generate the trigger tags */
247         if ((rc = parseRCPOT(spec, pkg, reqargs, reqtag, index))) {
248             freeStringBuf(sb);
249             FREE(progArgv);
250             FREE(argv);
251             poptFreeContext(optCon);
252             return rc;
253         }
254     } else {
255         headerAddEntry(pkg->header, progtag, RPM_STRING_TYPE, prog, 1);
256         if (*p) {
257             headerAddEntry(pkg->header, tag, RPM_STRING_TYPE, p, 1);
258         }
259         if (file) {
260             switch (parsePart) {
261               case PART_PRE:
262                 pkg->preInFile = strdup(file);
263                 break;
264               case PART_POST:
265                 pkg->postInFile = strdup(file);
266                 break;
267               case PART_PREUN:
268                 pkg->preUnFile = strdup(file);
269                 break;
270               case PART_POSTUN:
271                 pkg->postUnFile = strdup(file);
272                 break;
273               case PART_VERIFYSCRIPT:
274                 pkg->verifyFile = strdup(file);
275                 break;
276             }
277         }
278     }
279     
280     freeStringBuf(sb);
281     FREE(progArgv);
282     FREE(argv);
283     poptFreeContext(optCon);
284     
285     return nextPart;
286 }