rpm  4.5
parseScript.c
Go to the documentation of this file.
1 
6 #include "system.h"
7 
8 #define _RPMEVR_INTERNAL
9 #include "rpmbuild.h"
10 #include "debug.h"
11 
12 #include <rpmlua.h>
13 
14 /*@access StringBuf@*/ /* XXX compared with NULL */
15 /*@access poptContext @*/ /* compared with NULL */
16 
19 static int addTriggerIndex(Package pkg, const char *file,
20  const char *script, const char *prog)
21  /*@modifies pkg->triggerFiles @*/
22 {
23  struct TriggerFileEntry *tfe;
24  struct TriggerFileEntry *list = pkg->triggerFiles;
25  struct TriggerFileEntry *last = NULL;
26  int index = 0;
27 
28  while (list) {
29  last = list;
30  list = list->next;
31  }
32 
33  if (last)
34  index = last->index + 1;
35 
36  tfe = xcalloc(1, sizeof(*tfe));
37 
38  tfe->fileName = (file) ? xstrdup(file) : NULL;
39  tfe->script = (script && *script != '\0') ? xstrdup(script) : NULL;
40  tfe->prog = xstrdup(prog);
41  tfe->index = index;
42  tfe->next = NULL;
43 
44  if (last)
45  last->next = tfe;
46  else
47  pkg->triggerFiles = tfe;
48 
49  return index;
50 }
51 
52 /* these have to be global because of stupid compilers */
53 /*@unchecked@*/
54  /*@observer@*/ /*@null@*/ static const char *name = NULL;
55 /*@unchecked@*/
56  /*@observer@*/ /*@null@*/ static const char *prog = NULL;
57 /*@unchecked@*/
58  /*@observer@*/ /*@null@*/ static const char *file = NULL;
59 /*@unchecked@*/
60  static struct poptOption optionsTable[] = {
61  { NULL, 'p', POPT_ARG_STRING, &prog, 'p', NULL, NULL},
62  { NULL, 'n', POPT_ARG_STRING, &name, 'n', NULL, NULL},
63  { NULL, 'f', POPT_ARG_STRING, &file, 'f', NULL, NULL},
64  { 0, 0, 0, 0, 0, NULL, NULL}
65  };
66 
67 /* %trigger is a strange combination of %pre and Requires: behavior */
68 /* We can handle it by parsing the args before "--" in parseScript. */
69 /* We then pass the remaining arguments to parseRCPOT, along with */
70 /* an index we just determined. */
71 
72 /*@-boundswrite@*/
73 int parseScript(Spec spec, int parsePart)
74 {
75  /* There are a few options to scripts: */
76  /* <pkg> */
77  /* -n <pkg> */
78  /* -p <sh> */
79  /* -p "<sh> <args>..." */
80  /* -f <file> */
81 
82  char *p;
83  const char **progArgv = NULL;
84  int progArgc;
85  char *partname = NULL;
86  rpmTag reqtag = 0;
87  rpmTag tag = 0;
88  int tagflags = 0;
89  rpmTag progtag = 0;
90  int flag = PART_SUBNAME;
91  Package pkg;
92  StringBuf sb = NULL;
93  int nextPart;
94  int index;
95  char reqargs[BUFSIZ];
96 
97  int rc, argc;
98  int arg;
99  const char **argv = NULL;
100  poptContext optCon = NULL;
101 
102  reqargs[0] = '\0';
103  /*@-mods@*/
104  name = NULL;
105  prog = "/bin/sh";
106  file = NULL;
107  /*@=mods@*/
108 
109  /*@-branchstate@*/
110  switch (parsePart) {
111  case PART_PRE:
112  tag = RPMTAG_PREIN;
113  tagflags = RPMSENSE_SCRIPT_PRE;
114  progtag = RPMTAG_PREINPROG;
115  partname = "%pre";
116  break;
117  case PART_POST:
118  tag = RPMTAG_POSTIN;
119  tagflags = RPMSENSE_SCRIPT_POST;
120  progtag = RPMTAG_POSTINPROG;
121  partname = "%post";
122  break;
123  case PART_PREUN:
124  tag = RPMTAG_PREUN;
125  tagflags = RPMSENSE_SCRIPT_PREUN;
126  progtag = RPMTAG_PREUNPROG;
127  partname = "%preun";
128  break;
129  case PART_POSTUN:
130  tag = RPMTAG_POSTUN;
131  tagflags = RPMSENSE_SCRIPT_POSTUN;
132  progtag = RPMTAG_POSTUNPROG;
133  partname = "%postun";
134  break;
135  case PART_PRETRANS:
136  tag = RPMTAG_PRETRANS;
137  tagflags = 0;
138  progtag = RPMTAG_PRETRANSPROG;
139  partname = "%pretrans";
140  break;
141  case PART_POSTTRANS:
142  tag = RPMTAG_POSTTRANS;
143  tagflags = 0;
144  progtag = RPMTAG_POSTTRANSPROG;
145  partname = "%posttrans";
146  break;
147  case PART_VERIFYSCRIPT:
148  tag = RPMTAG_VERIFYSCRIPT;
149  tagflags = RPMSENSE_SCRIPT_VERIFY;
150  progtag = RPMTAG_VERIFYSCRIPTPROG;
151  partname = "%verifyscript";
152  break;
153  case PART_TRIGGERPREIN:
154  tag = RPMTAG_TRIGGERSCRIPTS;
155  tagflags = 0;
156  reqtag = RPMTAG_TRIGGERPREIN;
157  progtag = RPMTAG_TRIGGERSCRIPTPROG;
158  partname = "%triggerprein";
159  break;
160  case PART_TRIGGERIN:
161  tag = RPMTAG_TRIGGERSCRIPTS;
162  tagflags = 0;
163  reqtag = RPMTAG_TRIGGERIN;
164  progtag = RPMTAG_TRIGGERSCRIPTPROG;
165  partname = "%triggerin";
166  break;
167  case PART_TRIGGERUN:
168  tag = RPMTAG_TRIGGERSCRIPTS;
169  tagflags = 0;
170  reqtag = RPMTAG_TRIGGERUN;
171  progtag = RPMTAG_TRIGGERSCRIPTPROG;
172  partname = "%triggerun";
173  break;
174  case PART_TRIGGERPOSTUN:
175  tag = RPMTAG_TRIGGERSCRIPTS;
176  tagflags = 0;
177  reqtag = RPMTAG_TRIGGERPOSTUN;
178  progtag = RPMTAG_TRIGGERSCRIPTPROG;
179  partname = "%triggerpostun";
180  break;
181  }
182  /*@=branchstate@*/
183 
184  if (tag == RPMTAG_TRIGGERSCRIPTS) {
185  /* break line into two */
186  p = strstr(spec->line, "--");
187  if (!p) {
188  rpmError(RPMERR_BADSPEC, _("line %d: triggers must have --: %s\n"),
189  spec->lineNum, spec->line);
190  return RPMERR_BADSPEC;
191  }
192 
193  *p = '\0';
194  strcpy(reqargs, p + 2);
195  }
196 
197  if ((rc = poptParseArgvString(spec->line, &argc, &argv))) {
198  rpmError(RPMERR_BADSPEC, _("line %d: Error parsing %s: %s\n"),
199  spec->lineNum, partname, poptStrerror(rc));
200  return RPMERR_BADSPEC;
201  }
202 
203  optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
204  while ((arg = poptGetNextOpt(optCon)) > 0) {
205  switch (arg) {
206  case 'p':
207  if (prog[0] == '<') {
208  if (prog[strlen(prog)-1] != '>') {
210  _("line %d: internal script must end "
211  "with \'>\': %s\n"), spec->lineNum, prog);
212  rc = RPMERR_BADSPEC;
213  goto exit;
214  }
215  } else if (prog[0] == '%') {
216  /* XXX check well-formed macro? */
217  } else if (prog[0] != '/') {
219  _("line %d: script program must begin "
220  "with \'/\': %s\n"), spec->lineNum, prog);
221  rc = RPMERR_BADSPEC;
222  goto exit;
223  }
224  /*@switchbreak@*/ break;
225  case 'n':
226  flag = PART_NAME;
227  /*@switchbreak@*/ break;
228  }
229  }
230 
231  if (arg < -1) {
232  rpmError(RPMERR_BADSPEC, _("line %d: Bad option %s: %s\n"),
233  spec->lineNum,
234  poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
235  spec->line);
236  rc = RPMERR_BADSPEC;
237  goto exit;
238  }
239 
240  if (poptPeekArg(optCon)) {
241  /*@-mods@*/
242  if (name == NULL)
243  name = poptGetArg(optCon);
244  /*@=mods@*/
245  if (poptPeekArg(optCon)) {
246  rpmError(RPMERR_BADSPEC, _("line %d: Too many names: %s\n"),
247  spec->lineNum,
248  spec->line);
249  rc = RPMERR_BADSPEC;
250  goto exit;
251  }
252  }
253 
254  if (lookupPackage(spec, name, flag, &pkg)) {
255  rpmError(RPMERR_BADSPEC, _("line %d: Package does not exist: %s\n"),
256  spec->lineNum, spec->line);
257  rc = RPMERR_BADSPEC;
258  goto exit;
259  }
260 
261  if (tag != RPMTAG_TRIGGERSCRIPTS) {
262  if (headerIsEntry(pkg->header, progtag)) {
263  rpmError(RPMERR_BADSPEC, _("line %d: Second %s\n"),
264  spec->lineNum, partname);
265  rc = RPMERR_BADSPEC;
266  goto exit;
267  }
268  }
269 
270  if ((rc = poptParseArgvString(prog, &progArgc, &progArgv))) {
271  rpmError(RPMERR_BADSPEC, _("line %d: Error parsing %s: %s\n"),
272  spec->lineNum, partname, poptStrerror(rc));
273  rc = RPMERR_BADSPEC;
274  goto exit;
275  }
276 
277  sb = newStringBuf();
278  if ((rc = readLine(spec, STRIP_NOTHING)) > 0) {
279  nextPart = PART_NONE;
280  } else {
281  if (rc)
282  goto exit;
283  while (! (nextPart = isPart(spec->line))) {
284  appendStringBuf(sb, spec->line);
285  if ((rc = readLine(spec, STRIP_NOTHING)) > 0) {
286  nextPart = PART_NONE;
287  break;
288  }
289  if (rc)
290  goto exit;
291  }
292  }
294  p = getStringBuf(sb);
295 
296 #ifdef WITH_LUA
297  if (!strcmp(progArgv[0], "<lua>")) {
298  rpmlua lua = NULL; /* Global state. */
299  if (rpmluaCheckScript(lua, p, partname) != RPMRC_OK) {
300  rc = RPMERR_BADSPEC;
301  goto exit;
302  }
303  (void) rpmlibNeedsFeature(pkg->header,
304  "BuiltinLuaScripts", "4.2.2-1");
305  } else
306 #endif
307  if (progArgv[0][0] == '<') {
309  _("line %d: unsupported internal script: %s\n"),
310  spec->lineNum, progArgv[0]);
311  rc = RPMERR_BADSPEC;
312  goto exit;
313  } else {
314  (void) addReqProv(spec, pkg->header, RPMTAG_REQUIRENAME,
315  progArgv[0], NULL, (tagflags | RPMSENSE_INTERP), 0);
316  }
317 
318  /* Trigger script insertion is always delayed in order to */
319  /* get the index right. */
320  if (tag == RPMTAG_TRIGGERSCRIPTS) {
321  /* Add file/index/prog triple to the trigger file list */
322  index = addTriggerIndex(pkg, file, p, progArgv[0]);
323 
324  /* Generate the trigger tags */
325  if ((rc = parseRCPOT(spec, pkg, reqargs, reqtag, index, tagflags)))
326  goto exit;
327  } else {
328  if (progArgc == 1)
329  (void) headerAddEntry(pkg->header, progtag, RPM_STRING_TYPE,
330  *progArgv, progArgc);
331  else {
332  (void) rpmlibNeedsFeature(pkg->header,
333  "ScriptletInterpreterArgs", "4.0.3-1");
334  (void) headerAddEntry(pkg->header, progtag, RPM_STRING_ARRAY_TYPE,
335  progArgv, progArgc);
336  }
337 
338  if (*p != '\0')
339  (void) headerAddEntry(pkg->header, tag, RPM_STRING_TYPE, p, 1);
340 
341  if (file) {
342  switch (parsePart) {
343  case PART_PRE:
344  pkg->preInFile = xstrdup(file);
345  break;
346  case PART_POST:
347  pkg->postInFile = xstrdup(file);
348  break;
349  case PART_PREUN:
350  pkg->preUnFile = xstrdup(file);
351  break;
352  case PART_POSTUN:
353  pkg->postUnFile = xstrdup(file);
354  break;
355  case PART_PRETRANS:
356  pkg->preTransFile = xstrdup(file);
357  break;
358  case PART_POSTTRANS:
359  pkg->postTransFile = xstrdup(file);
360  break;
361  case PART_VERIFYSCRIPT:
362  pkg->verifyFile = xstrdup(file);
363  break;
364  }
365  }
366  }
367  rc = nextPart;
368 
369 exit:
370  sb = freeStringBuf(sb);
371  progArgv = _free(progArgv);
372  argv = _free(argv);
373  optCon = poptFreeContext(optCon);
374 
375  return rc;
376 }
377 /*@=boundswrite@*/