rpm  5.2.1
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 = 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  if (prog[strlen(prog)-1] != '>') {
219  _("line %d: internal script must end "
220  "with \'>\': %s\n"), spec->lineNum, prog);
221  rc = RPMRC_FAIL;
222  goto exit;
223  }
224  } else if (prog[0] == '%') {
225  /* XXX check well-formed macro? */
226  } else if (prog[0] != '/') {
228  _("line %d: script program must begin "
229  "with \'/\': %s\n"), spec->lineNum, prog);
230  rc = RPMRC_FAIL;
231  goto exit;
232  }
233  /*@switchbreak@*/ break;
234  case 'n':
235  flag = PART_NAME;
236  /*@switchbreak@*/ break;
237  }
238  }
239 
240  if (arg < -1) {
241  rpmlog(RPMLOG_ERR, _("line %d: Bad option %s: %s\n"),
242  spec->lineNum,
243  poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
244  spec->line);
245  rc = RPMRC_FAIL;
246  goto exit;
247  }
248 
249  if (poptPeekArg(optCon)) {
250  /*@-mods@*/
251  if (name == NULL)
252  name = poptGetArg(optCon);
253  /*@=mods@*/
254  if (poptPeekArg(optCon)) {
255  rpmlog(RPMLOG_ERR, _("line %d: Too many names: %s\n"),
256  spec->lineNum,
257  spec->line);
258  rc = RPMRC_FAIL;
259  goto exit;
260  }
261  }
262 
263  if (lookupPackage(spec, name, flag, &pkg) != RPMRC_OK) {
264  rpmlog(RPMLOG_ERR, _("line %d: Package does not exist: %s\n"),
265  spec->lineNum, spec->line);
266  rc = RPMRC_FAIL;
267  goto exit;
268  }
269 
270  if (tag != RPMTAG_TRIGGERSCRIPTS) {
271  if (headerIsEntry(pkg->header, progtag)) {
272  rpmlog(RPMLOG_ERR, _("line %d: Second %s\n"),
273  spec->lineNum, partname);
274  rc = RPMRC_FAIL;
275  goto exit;
276  }
277  }
278 
279  if ((rc = poptParseArgvString(prog, &progArgc, &progArgv))) {
280  rpmlog(RPMLOG_ERR, _("line %d: Error parsing %s: %s\n"),
281  spec->lineNum, partname, poptStrerror(rc));
282  rc = RPMRC_FAIL;
283  goto exit;
284  }
285 
286  iob = rpmiobNew(0);
287  if ((rc = readLine(spec, STRIP_NOTHING)) > 0) {
288  nextPart = PART_NONE;
289  } else {
290  if (rc)
291  goto exit;
292  while ((nextPart = isPart(spec)) == PART_NONE) {
293  iob = rpmiobAppend(iob, spec->line, 0);
294  if ((rc = readLine(spec, STRIP_NOTHING)) > 0) {
295  nextPart = PART_NONE;
296  break;
297  }
298  if (rc)
299  goto exit;
300  }
301  }
302  iob = rpmiobRTrim(iob);
303  p = rpmiobStr(iob);
304 
305 #ifdef WITH_LUA
306  if (!strcmp(progArgv[0], "<lua>")) {
307  rpmlua lua = NULL; /* Global state. */
308  if (rpmluaCheckScript(lua, p, partname) != RPMRC_OK) {
309  rc = RPMRC_FAIL;
310  goto exit;
311  }
312  (void) rpmlibNeedsFeature(pkg->header,
313  "BuiltinLuaScripts", "4.2.2-1");
314  } else
315 #endif
316 #ifdef WITH_FICL
317  if (!strcmp(progArgv[0], "<ficl>")) {
318  (void) rpmlibNeedsFeature(pkg->header,
319  "BuiltinFiclScripts", "5.2-1");
320  } else
321 #endif
322 #ifdef WITH_JS
323  if (!strcmp(progArgv[0], "<js>")) {
324  (void) rpmlibNeedsFeature(pkg->header,
325  "BuiltinJavaScript", "5.2-1");
326  } else
327 #endif
328 #ifdef WITH_PERLEMBED
329  if (!strcmp(progArgv[0], "<perl>")) {
330  (void) rpmlibNeedsFeature(pkg->header,
331  "BuiltinPerlScripts", "5.2-1");
332  } else
333 #endif
334 #ifdef WITH_PYTHONEMBED
335  if (!strcmp(progArgv[0], "<python>")) {
336  (void) rpmlibNeedsFeature(pkg->header,
337  "BuiltinPythonScripts", "5.2-1");
338  } else
339 #endif
340 #ifdef WITH_RUBYEMBED
341  if (!strcmp(progArgv[0], "<ruby>")) {
342  (void) rpmlibNeedsFeature(pkg->header,
343  "BuiltinRubyScripts", "5.2-1");
344  } else
345 #endif
346 #ifdef WITH_TCL
347  if (!strcmp(progArgv[0], "<tcl>")) {
348  (void) rpmlibNeedsFeature(pkg->header,
349  "BuiltinTclScripts", "5.2-1");
350  } else
351 #endif
352  if (progArgv[0][0] == '<') {
354  _("line %d: unsupported internal script: %s\n"),
355  spec->lineNum, progArgv[0]);
356  rc = RPMRC_FAIL;
357  goto exit;
358  } else
359  if (!(rpmExpandNumeric("%{?_disable_shell_interpreter_deps}")
360  && !strcmp(progArgv[0], "/bin/sh")))
361  {
362 
363  (void) addReqProv(spec, pkg->header, RPMTAG_REQUIRENAME,
364  progArgv[0], NULL, (tagflags | RPMSENSE_INTERP), 0);
365  }
366 
367  /* Trigger script insertion is always delayed in order to */
368  /* get the index right. */
369  if (tag == RPMTAG_TRIGGERSCRIPTS) {
370  /* Add file/index/prog triple to the trigger file list */
371  rpmuint32_t index = addTriggerIndex(pkg, file, p, progArgv[0]);
372 
373  /* Generate the trigger tags */
374  if ((rc = parseRCPOT(spec, pkg, reqargs, reqtag, index, tagflags)))
375  goto exit;
376  } else {
377  if (progArgc == 1) {
378  he->tag = progtag;
379  he->t = RPM_STRING_TYPE;
380  he->p.str = *progArgv;
381  he->c = progArgc;
382  xx = headerPut(pkg->header, he, 0);
383  } else {
384  (void) rpmlibNeedsFeature(pkg->header,
385  "ScriptletInterpreterArgs", "4.0.3-1");
386  he->tag = progtag;
387  he->t = RPM_STRING_ARRAY_TYPE;
388  he->p.argv = progArgv;
389  he->c = progArgc;
390  xx = headerPut(pkg->header, he, 0);
391  }
392 
393  if (*p != '\0') {
394  he->tag = tag;
395  he->t = RPM_STRING_TYPE;
396  he->p.str = p;
397  he->c = 1;
398  xx = headerPut(pkg->header, he, 0);
399  }
400 
401  if (file) {
402  switch (parsePart) {
403  case PART_PRE:
404  pkg->preInFile = xstrdup(file);
405  break;
406  case PART_POST:
407  pkg->postInFile = xstrdup(file);
408  break;
409  case PART_PREUN:
410  pkg->preUnFile = xstrdup(file);
411  break;
412  case PART_POSTUN:
413  pkg->postUnFile = xstrdup(file);
414  break;
415  case PART_PRETRANS:
416  pkg->preTransFile = xstrdup(file);
417  break;
418  case PART_POSTTRANS:
419  pkg->postTransFile = xstrdup(file);
420  break;
421  case PART_VERIFYSCRIPT:
422  pkg->verifyFile = xstrdup(file);
423  break;
424  case PART_SANITYCHECK:
425  pkg->sanityCheckFile = xstrdup(file);
426  break;
427  }
428  }
429  }
430  rc = (rpmRC) nextPart;
431 
432 exit:
433  iob = rpmiobFree(iob);
434  progArgv = _free(progArgv);
435  argv = _free(argv);
436  optCon = poptFreeContext(optCon);
437 
438  return rc;
439 }