rpm  5.4.10
parseScript.c
Go to the documentation of this file.
1 
6 #include "system.h"
7 
8 #include <rpmio.h>
9 #include <rpmiotypes.h>
10 #include <rpmlog.h>
11 #define _RPMEVR_INTERNAL
12 #include "rpmbuild.h"
13 #include "debug.h"
14 
15 #include <rpmlua.h>
16 
17 /*@access poptContext @*/ /* compared with NULL */
18 
21 static rpmuint32_t addTriggerIndex(Package pkg, const char *file,
22  const char *script, const char *prog)
23  /*@modifies pkg->triggerFiles @*/
24 {
25  struct TriggerFileEntry *tfe;
26  struct TriggerFileEntry *list = pkg->triggerFiles;
27  struct TriggerFileEntry *last = NULL;
28  rpmuint32_t index = 0;
29 
30  while (list) {
31  last = list;
32  list = list->next;
33  }
34 
35  if (last)
36  index = last->index + 1;
37 
38  tfe = xcalloc(1, sizeof(*tfe));
39 
40  tfe->fileName = (file) ? xstrdup(file) : NULL;
41  tfe->script = (script && *script != '\0') ? xstrdup(script) : NULL;
42  tfe->prog = xstrdup(prog);
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 /* these have to be global because of stupid compilers */
55 /*@unchecked@*/
56  /*@observer@*/ /*@null@*/ static const char *name = NULL;
57 /*@unchecked@*/
58  /*@observer@*/ /*@null@*/ static const char *prog = NULL;
59 /*@unchecked@*/
60  /*@observer@*/ /*@null@*/ static const char *file = NULL;
61 /*@unchecked@*/
62  static struct poptOption optionsTable[] = {
63  { NULL, 'p', POPT_ARG_STRING, &prog, 'p', NULL, NULL},
64  { NULL, 'n', POPT_ARG_STRING, &name, 'n', NULL, NULL},
65  { NULL, 'f', POPT_ARG_STRING, &file, 'f', NULL, NULL},
66  { 0, 0, 0, 0, 0, NULL, NULL}
67  };
68 
69 /* %trigger is a strange combination of %pre and Requires: behavior */
70 /* We can handle it by parsing the args before "--" in parseScript. */
71 /* We then pass the remaining arguments to parseRCPOT, along with */
72 /* an index we just determined. */
73 
74 int parseScript(Spec spec, int parsePart)
75 {
76  HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he));
77  int xx;
78 
79  /* There are a few options to scripts: */
80  /* <pkg> */
81  /* -n <pkg> */
82  /* -p <sh> */
83  /* -p "<sh> <args>..." */
84  /* -f <file> */
85 
86  char *p;
87  const char **progArgv = NULL;
88  int progArgc;
89  char *partname = NULL;
90  rpmTag reqtag = 0;
91  rpmTag tag = 0;
92  rpmsenseFlags tagflags = 0;
93  rpmTag progtag = 0;
94  int flag = PART_SUBNAME;
95  Package pkg;
96  rpmiob iob = NULL;
97  rpmParseState nextPart;
98  char reqargs[BUFSIZ];
99 
100  int argc;
101  int arg;
102  const char **argv = NULL;
103  poptContext optCon = NULL;
104  rpmRC rc;
105 
106  reqargs[0] = '\0';
107  /*@-mods@*/
108  name = NULL;
109  prog = "/bin/sh";
110  file = NULL;
111  /*@=mods@*/
112 
113  switch (parsePart) {
114  case PART_PRE:
115  tag = RPMTAG_PREIN;
116  tagflags = RPMSENSE_SCRIPT_PRE;
117  progtag = RPMTAG_PREINPROG;
118  partname = "%pre";
119  break;
120  case PART_POST:
121  tag = RPMTAG_POSTIN;
122  tagflags = RPMSENSE_SCRIPT_POST;
123  progtag = RPMTAG_POSTINPROG;
124  partname = "%post";
125  break;
126  case PART_PREUN:
127  tag = RPMTAG_PREUN;
128  tagflags = RPMSENSE_SCRIPT_PREUN;
129  progtag = RPMTAG_PREUNPROG;
130  partname = "%preun";
131  break;
132  case PART_POSTUN:
133  tag = RPMTAG_POSTUN;
134  tagflags = RPMSENSE_SCRIPT_POSTUN;
135  progtag = RPMTAG_POSTUNPROG;
136  partname = "%postun";
137  break;
138  case PART_PRETRANS:
139  tag = RPMTAG_PRETRANS;
140  tagflags = 0;
141  progtag = RPMTAG_PRETRANSPROG;
142  partname = "%pretrans";
143  break;
144  case PART_POSTTRANS:
145  tag = RPMTAG_POSTTRANS;
146  tagflags = 0;
147  progtag = RPMTAG_POSTTRANSPROG;
148  partname = "%posttrans";
149  break;
150  case PART_VERIFYSCRIPT:
151  tag = RPMTAG_VERIFYSCRIPT;
152  tagflags = RPMSENSE_SCRIPT_VERIFY;
153  progtag = RPMTAG_VERIFYSCRIPTPROG;
154  partname = "%verifyscript";
155  break;
156  case PART_TRIGGERPREIN:
157  tag = RPMTAG_TRIGGERSCRIPTS;
158  tagflags = 0;
159  reqtag = RPMTAG_TRIGGERPREIN;
160  progtag = RPMTAG_TRIGGERSCRIPTPROG;
161  partname = "%triggerprein";
162  break;
163  case PART_TRIGGERIN:
164  tag = RPMTAG_TRIGGERSCRIPTS;
165  tagflags = 0;
166  reqtag = RPMTAG_TRIGGERIN;
167  progtag = RPMTAG_TRIGGERSCRIPTPROG;
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  partname = "%triggerun";
176  break;
177  case PART_TRIGGERPOSTUN:
178  tag = RPMTAG_TRIGGERSCRIPTS;
179  tagflags = 0;
180  reqtag = RPMTAG_TRIGGERPOSTUN;
181  progtag = RPMTAG_TRIGGERSCRIPTPROG;
182  partname = "%triggerpostun";
183  break;
184  /* support "%sanitycheck" script/section */
185  case PART_SANITYCHECK:
186  tag = RPMTAG_SANITYCHECK;
187  tagflags = RPMSENSE_SCRIPT_SANITYCHECK;
188  progtag = RPMTAG_SANITYCHECKPROG;
189  partname = "%sanitycheck";
190  break;
191  }
192 
193  if (tag == RPMTAG_TRIGGERSCRIPTS) {
194  /* break line into two */
195  p = strstr(spec->line, "--");
196  if (!p) {
197  rpmlog(RPMLOG_ERR, _("line %d: triggers must have --: %s\n"),
198  spec->lineNum, spec->line);
199  return RPMRC_FAIL;
200  }
201 
202  *p = '\0';
203  strcpy(reqargs, p + 2);
204  }
205 
206  if ((rc = poptParseArgvString(spec->line, &argc, &argv))) {
207  rpmlog(RPMLOG_ERR, _("line %d: Error parsing %s: %s\n"),
208  spec->lineNum, partname, poptStrerror(rc));
209  return RPMRC_FAIL;
210  }
211 
212  optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
213  while ((arg = poptGetNextOpt(optCon)) > 0) {
214  switch (arg) {
215  case 'p':
216  if (prog[0] == '<') {
217  const char * s = prog;
218  while (s && s[1] && s[1] != '>')
219  s++;
220  if (s[1] != '>') {
222  _("line %d: embedded interpreter token must end "
223  "with \'>\': %s\n"), spec->lineNum, prog);
224  rc = RPMRC_FAIL;
225  goto exit;
226  }
227  } else if (prog[0] == '%') {
228  /* XXX check well-formed macro? */
229  } else if (prog[0] != '/') {
231  _("line %d: script program must begin "
232  "with \'/\': %s\n"), spec->lineNum, prog);
233  rc = RPMRC_FAIL;
234  goto exit;
235  }
236  /*@switchbreak@*/ break;
237  case 'n':
238  flag = PART_NAME;
239  /*@switchbreak@*/ break;
240  }
241  }
242 
243  if (arg < -1) {
244  rpmlog(RPMLOG_ERR, _("line %d: Bad option %s: %s\n"),
245  spec->lineNum,
246  poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
247  spec->line);
248  rc = RPMRC_FAIL;
249  goto exit;
250  }
251 
252  if (poptPeekArg(optCon)) {
253  /*@-mods@*/
254  if (name == NULL)
255  name = poptGetArg(optCon);
256  /*@=mods@*/
257  if (poptPeekArg(optCon)) {
258  rpmlog(RPMLOG_ERR, _("line %d: Too many names: %s\n"),
259  spec->lineNum,
260  spec->line);
261  rc = RPMRC_FAIL;
262  goto exit;
263  }
264  }
265 
266  if (lookupPackage(spec, name, flag, &pkg) != RPMRC_OK) {
267  rpmlog(RPMLOG_ERR, _("line %d: Package does not exist: %s\n"),
268  spec->lineNum, spec->line);
269  rc = RPMRC_FAIL;
270  goto exit;
271  }
272 
273  if (tag != RPMTAG_TRIGGERSCRIPTS) {
274  if (headerIsEntry(pkg->header, progtag)) {
275  rpmlog(RPMLOG_ERR, _("line %d: Second %s\n"),
276  spec->lineNum, partname);
277  rc = RPMRC_FAIL;
278  goto exit;
279  }
280  }
281 
282  if ((rc = poptParseArgvString(prog, &progArgc, &progArgv))) {
283  rpmlog(RPMLOG_ERR, _("line %d: Error parsing %s: %s\n"),
284  spec->lineNum, partname, poptStrerror(rc));
285  rc = RPMRC_FAIL;
286  goto exit;
287  }
288 
289  iob = rpmiobNew(0);
290  if ((rc = readLine(spec, STRIP_NOTHING)) > 0) {
291  nextPart = PART_NONE;
292  } else {
293  if (rc)
294  goto exit;
295  while ((nextPart = isPart(spec)) == PART_NONE) {
296  iob = rpmiobAppend(iob, spec->line, 0);
297  if ((rc = readLine(spec, STRIP_NOTHING)) > 0) {
298  nextPart = PART_NONE;
299  break;
300  }
301  if (rc)
302  goto exit;
303  }
304  }
305  iob = rpmiobRTrim(iob);
306  p = rpmiobStr(iob);
307 
308 #if __WORDSIZE == 64 /* XXX lame, whatever.. :p */
309 #define SO_EXT "()(64bit)"
310 #else
311 #define SO_EXT ""
312 #endif
313 
314 #ifdef WITH_LUA
315  if (!strcmp(progArgv[0], "<lua>")) {
316  rpmlua lua = NULL; /* Global state. */
317  if (rpmluaCheckScript(lua, p, partname) != RPMRC_OK) {
318  rc = RPMRC_FAIL;
319  goto exit;
320  }
321  (void) rpmlibNeedsFeature(pkg->header,
322  "BuiltinLuaScripts", "4.2.2-1");
323  } else
324 #endif
325 #ifdef WITH_AUGEAS
326  if (!strcmp(progArgv[0], "<augeas>")) {
327  (void) rpmlibNeedsFeature(pkg->header,
328  "BuiltinAugeasScripts", "5.3-1");
329  } else
330 #endif
331 #ifdef WITH_FICL
332  if (!strcmp(progArgv[0], "<ficl>")) {
333  (void) rpmlibNeedsFeature(pkg->header,
334  "BuiltinFiclScripts", "5.2-1");
335  } else
336 #endif
337 #ifdef WITH_GPSEE
338  if (!strcmp(progArgv[0], "<js>")) {
339  (void) rpmlibNeedsFeature(pkg->header,
340  "BuiltinJavaScript", "5.2-1");
341  } else
342 #endif
343 #ifdef WITH_PERLEMBED
344  if (!strcmp(progArgv[0], "<perl>")) {
345  (void) rpmlibNeedsFeature(pkg->header,
346  "BuiltinPerlScripts", "5.2-1");
347  addReqProv(NULL, pkg->header, RPMTAG_REQUIRENAME, "rpmperl.so" SO_EXT, NULL, RPMSENSE_INTERP, 0);
348  } else
349 #endif
350 #ifdef WITH_PYTHONEMBED
351  if (!strcmp(progArgv[0], "<python>")) {
352  (void) rpmlibNeedsFeature(pkg->header,
353  "BuiltinPythonScripts", "5.2-1");
354  addReqProv(NULL, pkg->header, RPMTAG_REQUIRENAME, "rpmpython.so" SO_EXT, NULL, RPMSENSE_INTERP, 0);
355  } else
356 #endif
357 #ifdef WITH_RUBYEMBED
358  if (!strcmp(progArgv[0], "<ruby>")) {
359  (void) rpmlibNeedsFeature(pkg->header,
360  "BuiltinRubyScripts", "5.2-1");
361  addReqProv(NULL, pkg->header, RPMTAG_REQUIRENAME, "rpmruby.so" SO_EXT, NULL, RPMSENSE_INTERP, 0);
362  } else
363 #endif
364 #ifdef WITH_SEMANAGE
365  if (!strcmp(progArgv[0], "<spook>")) {
366  (void) rpmlibNeedsFeature(pkg->header,
367  "BuiltinSpookScripts", "5.3-1");
368  } else
369 #endif
370 #ifdef WITH_SQLITE
371  if (!strcmp(progArgv[0], "<sql>")) {
372  (void) rpmlibNeedsFeature(pkg->header,
373  "BuiltinSqlScripts", "5.3-1");
374  } else
375 #endif
376 #ifdef WITH_SQUIRREL
377  if (!strcmp(progArgv[0], "<squirrel>")) {
378  (void) rpmlibNeedsFeature(pkg->header,
379  "BuiltinSquirrelScripts", "5.2-1");
380  addReqProv(NULL, pkg->header, RPMTAG_REQUIRENAME, "rpmsquirrel.so" SO_EXT, NULL, RPMSENSE_INTERP, 0);
381  } else
382 #endif
383 #ifdef WITH_TCL
384  if (!strcmp(progArgv[0], "<tcl>")) {
385  (void) rpmlibNeedsFeature(pkg->header,
386  "BuiltinTclScripts", "5.2-1");
387  addReqProv(NULL, pkg->header, RPMTAG_REQUIRENAME, "rpmtcl.so" SO_EXT, NULL, RPMSENSE_INTERP, 0);
388  } else
389 #endif
390  if (progArgv[0][0] == '<') {
392  _("line %d: unsupported internal script: %s\n"),
393  spec->lineNum, progArgv[0]);
394  rc = RPMRC_FAIL;
395  goto exit;
396  } else
397  if (!(rpmExpandNumeric("%{?_disable_shell_interpreter_deps}")
398  && !strcmp(progArgv[0], "/bin/sh")))
399  {
400 
401  (void) addReqProv(spec, pkg->header, RPMTAG_REQUIRENAME,
402  progArgv[0], NULL, (tagflags | RPMSENSE_INTERP), 0);
403  }
404 
405  /* Trigger script insertion is always delayed in order to */
406  /* get the index right. */
407  if (tag == RPMTAG_TRIGGERSCRIPTS) {
408  /* Add file/index/prog triple to the trigger file list */
409  rpmuint32_t index = addTriggerIndex(pkg, file, p, progArgv[0]);
410 
411  /* Generate the trigger tags */
412  if ((rc = parseRCPOT(spec, pkg, reqargs, reqtag, index, tagflags)))
413  goto exit;
414  } else {
415  if (progArgc == 1) {
416  he->tag = progtag;
417  he->t = RPM_STRING_TYPE;
418  he->p.str = *progArgv;
419  he->c = progArgc;
420  xx = headerPut(pkg->header, he, 0);
421  } else {
422  (void) rpmlibNeedsFeature(pkg->header,
423  "ScriptletInterpreterArgs", "4.0.3-1");
424  he->tag = progtag;
425  he->t = RPM_STRING_ARRAY_TYPE;
426  he->p.argv = progArgv;
427  he->c = progArgc;
428  xx = headerPut(pkg->header, he, 0);
429  }
430 
431  if (*p != '\0') {
432  he->tag = tag;
433  he->t = RPM_STRING_TYPE;
434  he->p.str = p;
435  he->c = 1;
436  xx = headerPut(pkg->header, he, 0);
437  }
438 
439  if (file) {
440  switch (parsePart) {
441  case PART_PRE:
442  pkg->preInFile = xstrdup(file);
443  break;
444  case PART_POST:
445  pkg->postInFile = xstrdup(file);
446  break;
447  case PART_PREUN:
448  pkg->preUnFile = xstrdup(file);
449  break;
450  case PART_POSTUN:
451  pkg->postUnFile = xstrdup(file);
452  break;
453  case PART_PRETRANS:
454  pkg->preTransFile = xstrdup(file);
455  break;
456  case PART_POSTTRANS:
457  pkg->postTransFile = xstrdup(file);
458  break;
459  case PART_VERIFYSCRIPT:
460  pkg->verifyFile = xstrdup(file);
461  break;
462  case PART_SANITYCHECK:
463  pkg->sanityCheckFile = xstrdup(file);
464  break;
465  }
466  }
467  }
468  rc = (rpmRC) nextPart;
469 
470 exit:
471  iob = rpmiobFree(iob);
472  progArgv = _free(progArgv);
473  argv = _free(argv);
474  optCon = poptFreeContext(optCon);
475 
476  return rc;
477 }