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;
185  tag = RPMTAG_TRIGGERSCRIPTS;
186  tagflags = 0;
187  reqtag = RPMTAG_TRIGGERPRETRANSIN;
188  progtag = RPMTAG_TRIGGERSCRIPTPROG;
189  partname = "%triggerpretransin";
190  break;
192  tag = RPMTAG_TRIGGERSCRIPTS;
193  tagflags = 0;
194  reqtag = RPMTAG_TRIGGERPRETRANSUN;
195  progtag = RPMTAG_TRIGGERSCRIPTPROG;
196  partname = "%triggerpretransun";
197  break;
199  tag = RPMTAG_TRIGGERSCRIPTS;
200  tagflags = 0;
201  reqtag = RPMTAG_TRIGGERPOSTTRANSIN;
202  progtag = RPMTAG_TRIGGERSCRIPTPROG;
203  partname = "%triggerposttransin";
204  break;
206  tag = RPMTAG_TRIGGERSCRIPTS;
207  tagflags = 0;
208  reqtag = RPMTAG_TRIGGERPOSTTRANSUN;
209  progtag = RPMTAG_TRIGGERSCRIPTPROG;
210  partname = "%triggerposttransun";
211  break;
212  /* support "%sanitycheck" script/section */
213  case PART_SANITYCHECK:
214  tag = RPMTAG_SANITYCHECK;
215  tagflags = RPMSENSE_SCRIPT_SANITYCHECK;
216  progtag = RPMTAG_SANITYCHECKPROG;
217  partname = "%sanitycheck";
218  break;
219  }
220 
221  if (tag == RPMTAG_TRIGGERSCRIPTS) {
222  /* break line into two */
223  p = strstr(spec->line, "--");
224  if (!p) {
225  rpmlog(RPMLOG_ERR, _("line %d: triggers must have --: %s\n"),
226  spec->lineNum, spec->line);
227  return RPMRC_FAIL;
228  }
229 
230  *p = '\0';
231  strcpy(reqargs, p + 2);
232  }
233 
234  if ((rc = poptParseArgvString(spec->line, &argc, &argv))) {
235  rpmlog(RPMLOG_ERR, _("line %d: Error parsing %s: %s\n"),
236  spec->lineNum, partname, poptStrerror(rc));
237  return RPMRC_FAIL;
238  }
239 
240  optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
241  while ((arg = poptGetNextOpt(optCon)) > 0) {
242  switch (arg) {
243  case 'p':
244  if (prog[0] == '<') {
245  const char * s = prog;
246  while (s && s[1] && s[1] != '>')
247  s++;
248  if (s[1] != '>') {
250  _("line %d: embedded interpreter token must end "
251  "with \'>\': %s\n"), spec->lineNum, prog);
252  rc = RPMRC_FAIL;
253  goto exit;
254  }
255  } else if (prog[0] == '%') {
256  /* XXX check well-formed macro? */
257  } else if (prog[0] != '/') {
259  _("line %d: script program must begin "
260  "with \'/\': %s\n"), spec->lineNum, prog);
261  rc = RPMRC_FAIL;
262  goto exit;
263  }
264  /*@switchbreak@*/ break;
265  case 'n':
266  flag = PART_NAME;
267  /*@switchbreak@*/ break;
268  }
269  }
270 
271  if (arg < -1) {
272  rpmlog(RPMLOG_ERR, _("line %d: Bad option %s: %s\n"),
273  spec->lineNum,
274  poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
275  spec->line);
276  rc = RPMRC_FAIL;
277  goto exit;
278  }
279 
280  if (poptPeekArg(optCon)) {
281  /*@-mods@*/
282  if (name == NULL)
283  name = poptGetArg(optCon);
284  /*@=mods@*/
285  if (poptPeekArg(optCon)) {
286  rpmlog(RPMLOG_ERR, _("line %d: Too many names: %s\n"),
287  spec->lineNum,
288  spec->line);
289  rc = RPMRC_FAIL;
290  goto exit;
291  }
292  }
293 
294  if (lookupPackage(spec, name, flag, &pkg) != RPMRC_OK) {
295  rpmlog(RPMLOG_ERR, _("line %d: Package does not exist: %s\n"),
296  spec->lineNum, spec->line);
297  rc = RPMRC_FAIL;
298  goto exit;
299  }
300 
301  if (tag != RPMTAG_TRIGGERSCRIPTS) {
302  if (headerIsEntry(pkg->header, progtag)) {
303  rpmlog(RPMLOG_ERR, _("line %d: Second %s\n"),
304  spec->lineNum, partname);
305  rc = RPMRC_FAIL;
306  goto exit;
307  }
308  }
309 
310  if ((rc = poptParseArgvString(prog, &progArgc, &progArgv))) {
311  rpmlog(RPMLOG_ERR, _("line %d: Error parsing %s: %s\n"),
312  spec->lineNum, partname, poptStrerror(rc));
313  rc = RPMRC_FAIL;
314  goto exit;
315  }
316 
317  iob = rpmiobNew(0);
318  if ((rc = readLine(spec, STRIP_NOTHING)) > 0) {
319  nextPart = PART_NONE;
320  } else {
321  if (rc)
322  goto exit;
323  while ((nextPart = isPart(spec)) == PART_NONE) {
324  iob = rpmiobAppend(iob, spec->line, 0);
325  if ((rc = readLine(spec, STRIP_NOTHING)) > 0) {
326  nextPart = PART_NONE;
327  break;
328  }
329  if (rc)
330  goto exit;
331  }
332  }
333  iob = rpmiobRTrim(iob);
334  p = rpmiobStr(iob);
335 
336 #if __WORDSIZE == 64 /* XXX lame, whatever.. :p */
337 #define SO_EXT "()(64bit)"
338 #else
339 #define SO_EXT ""
340 #endif
341 
342 #ifdef WITH_LUA
343  if (!strcmp(progArgv[0], "<lua>")) {
344  rpmlua lua = NULL; /* Global state. */
345  if (rpmluaCheckScript(lua, p, partname) != RPMRC_OK) {
346  rc = RPMRC_FAIL;
347  goto exit;
348  }
349  (void) rpmlibNeedsFeature(pkg->header,
350  "BuiltinLuaScripts", "4.2.2-1");
351  } else
352 #endif
353 #ifdef WITH_AUGEAS
354  if (!strcmp(progArgv[0], "<augeas>")) {
355  (void) rpmlibNeedsFeature(pkg->header,
356  "BuiltinAugeasScripts", "5.3-1");
357  } else
358 #endif
359 #ifdef WITH_FICL
360  if (!strcmp(progArgv[0], "<ficl>")) {
361  (void) rpmlibNeedsFeature(pkg->header,
362  "BuiltinFiclScripts", "5.2-1");
363  } else
364 #endif
365 #ifdef WITH_GPSEE
366  if (!strcmp(progArgv[0], "<js>")) {
367  (void) rpmlibNeedsFeature(pkg->header,
368  "BuiltinJavaScript", "5.2-1");
369  } else
370 #endif
371 #ifdef WITH_PERLEMBED
372  if (!strcmp(progArgv[0], "<perl>")) {
373  (void) rpmlibNeedsFeature(pkg->header,
374  "BuiltinPerlScripts", "5.2-1");
375  addReqProv(NULL, pkg->header, RPMTAG_REQUIRENAME, "rpmperl.so" SO_EXT, NULL, RPMSENSE_INTERP, 0);
376  } else
377 #endif
378 #ifdef WITH_PYTHONEMBED
379  if (!strcmp(progArgv[0], "<python>")) {
380  (void) rpmlibNeedsFeature(pkg->header,
381  "BuiltinPythonScripts", "5.2-1");
382  addReqProv(NULL, pkg->header, RPMTAG_REQUIRENAME, "rpmpython.so" SO_EXT, NULL, RPMSENSE_INTERP, 0);
383  } else
384 #endif
385 #ifdef WITH_RUBYEMBED
386  if (!strcmp(progArgv[0], "<ruby>")) {
387  (void) rpmlibNeedsFeature(pkg->header,
388  "BuiltinRubyScripts", "5.2-1");
389  addReqProv(NULL, pkg->header, RPMTAG_REQUIRENAME, "rpmruby.so" SO_EXT, NULL, RPMSENSE_INTERP, 0);
390  } else
391 #endif
392 #ifdef WITH_SEMANAGE
393  if (!strcmp(progArgv[0], "<spook>")) {
394  (void) rpmlibNeedsFeature(pkg->header,
395  "BuiltinSpookScripts", "5.3-1");
396  } else
397 #endif
398 #ifdef WITH_SQLITE
399  if (!strcmp(progArgv[0], "<sql>")) {
400  (void) rpmlibNeedsFeature(pkg->header,
401  "BuiltinSqlScripts", "5.3-1");
402  } else
403 #endif
404 #ifdef WITH_SQUIRREL
405  if (!strcmp(progArgv[0], "<squirrel>")) {
406  (void) rpmlibNeedsFeature(pkg->header,
407  "BuiltinSquirrelScripts", "5.2-1");
408  addReqProv(NULL, pkg->header, RPMTAG_REQUIRENAME, "rpmsquirrel.so" SO_EXT, NULL, RPMSENSE_INTERP, 0);
409  } else
410 #endif
411 #ifdef WITH_TCL
412  if (!strcmp(progArgv[0], "<tcl>")) {
413  (void) rpmlibNeedsFeature(pkg->header,
414  "BuiltinTclScripts", "5.2-1");
415  addReqProv(NULL, pkg->header, RPMTAG_REQUIRENAME, "rpmtcl.so" SO_EXT, NULL, RPMSENSE_INTERP, 0);
416  } else
417 #endif
418  if (progArgv[0][0] == '<') {
420  _("line %d: unsupported internal script: %s\n"),
421  spec->lineNum, progArgv[0]);
422  rc = RPMRC_FAIL;
423  goto exit;
424  } else
425  if (!(rpmExpandNumeric("%{?_disable_shell_interpreter_deps}")
426  && !strcmp(progArgv[0], "/bin/sh")))
427  {
428 
429  (void) addReqProv(spec, pkg->header, RPMTAG_REQUIRENAME,
430  progArgv[0], NULL, (tagflags | RPMSENSE_INTERP), 0);
431  }
432 
433  /* Trigger script insertion is always delayed in order to */
434  /* get the index right. */
435  if (tag == RPMTAG_TRIGGERSCRIPTS) {
436  /* Add file/index/prog triple to the trigger file list */
437  rpmuint32_t index = addTriggerIndex(pkg, file, p, progArgv[0]);
438 
439  /* Generate the trigger tags */
440  if ((rc = parseRCPOT(spec, pkg, reqargs, reqtag, index, tagflags)))
441  goto exit;
442  } else {
443  if (progArgc == 1) {
444  he->tag = progtag;
445  he->t = RPM_STRING_TYPE;
446  he->p.str = *progArgv;
447  he->c = progArgc;
448  xx = headerPut(pkg->header, he, 0);
449  } else {
450  (void) rpmlibNeedsFeature(pkg->header,
451  "ScriptletInterpreterArgs", "4.0.3-1");
452  he->tag = progtag;
453  he->t = RPM_STRING_ARRAY_TYPE;
454  he->p.argv = progArgv;
455  he->c = progArgc;
456  xx = headerPut(pkg->header, he, 0);
457  }
458 
459  if (*p != '\0') {
460  he->tag = tag;
461  he->t = RPM_STRING_TYPE;
462  he->p.str = p;
463  he->c = 1;
464  xx = headerPut(pkg->header, he, 0);
465  }
466 
467  if (file) {
468  switch (parsePart) {
469  case PART_PRE:
470  pkg->preInFile = xstrdup(file);
471  break;
472  case PART_POST:
473  pkg->postInFile = xstrdup(file);
474  break;
475  case PART_PREUN:
476  pkg->preUnFile = xstrdup(file);
477  break;
478  case PART_POSTUN:
479  pkg->postUnFile = xstrdup(file);
480  break;
481  case PART_PRETRANS:
482  pkg->preTransFile = xstrdup(file);
483  break;
484  case PART_POSTTRANS:
485  pkg->postTransFile = xstrdup(file);
486  break;
487  case PART_VERIFYSCRIPT:
488  pkg->verifyFile = xstrdup(file);
489  break;
490  case PART_SANITYCHECK:
491  pkg->sanityCheckFile = xstrdup(file);
492  break;
493  }
494  }
495  }
496  rc = (rpmRC) nextPart;
497 
498 exit:
499  iob = rpmiobFree(iob);
500  progArgv = _free(progArgv);
501  argv = _free(argv);
502  optCon = poptFreeContext(optCon);
503 
504  return rc;
505 }
rpmTagType t
Definition: rpmtag.h:505
char * fileName
Definition: rpmspec.h:26
rpmiob rpmiobRTrim(rpmiob iob)
Trim trailing white space.
Definition: rpmiob.c:67
const char * str
Definition: rpmtag.h:72
rpmTag tag
Definition: rpmtag.h:504
const char ** argv
Definition: rpmtag.h:74
static const char * prog
Definition: parseScript.c:58
int rpmluaCheckScript(rpmlua _lua, const char *script, const char *name)
rpmParseState isPart(Spec spec)
Check line for section separator, return next parser state.
Definition: parseSpec.c:68
int headerIsEntry(Header h, rpmTag tag)
Check if tag is in header.
Definition: header.c:1431
int parseScript(Spec spec, int parsePart)
Parse %pre et al scriptlets from a spec file.
Definition: parseScript.c:74
const char * postInFile
Definition: rpmspec.h:223
char * xstrdup(const char *str)
Definition: rpmmalloc.c:322
#define SO_EXT
int headerPut(Header h, HE_t he, unsigned int flags)
Add or append tag container to header.
Definition: header.c:2285
char * prog
Definition: rpmspec.h:30
int addReqProv(Spec spec, Header h, rpmTag tagN, const char *N, const char *EVR, rpmsenseFlags Flags, rpmuint32_t index)
Add dependency to header, filtering duplicates.
Definition: reqprov.c:16
rpmRC lookupPackage(Spec spec, const char *name, int flag, Package *pkg)
Find sub-package control structure by name.
Definition: spec.c:82
#define PART_NAME
Definition: rpmbuild.h:49
rpmiob rpmiobFree(rpmiob iob)
Destroy a I/O buffer instance.
static void rpmlog(int code, const char *fmt,...)
Definition: rpmlog.h:299
rpmiob rpmiobAppend(rpmiob iob, const char *s, size_t nl)
Append string to I/O buffer.
Definition: rpmiob.c:78
int readLine(Spec spec, rpmStripFlags strip)
Read next line from spec file.
Definition: parseSpec.c:353
static rpmuint32_t addTriggerIndex(Package pkg, const char *file, const char *script, const char *prog)
Definition: parseScript.c:21
char * alloca()
Yet Another syslog(3) API clone.
Header header
Definition: rpmspec.h:210
unsigned int rpmuint32_t
Definition: rpmiotypes.h:25
struct _HE_s * HE_t
Definition: rpmtag.h:58
void * xcalloc(size_t nmemb, size_t size)
Definition: rpmmalloc.c:301
char * line
Definition: rpmspec.h:133
#define PART_SUBNAME
Definition: rpmbuild.h:48
enum evrFlags_e rpmsenseFlags
Definition: rpmevr.h:72
rpmTagData p
Definition: rpmtag.h:507
struct TriggerFileEntry * triggerFiles
Definition: rpmspec.h:241
rpmTagCount c
Definition: rpmtag.h:508
The structure used to store values parsed from a spec file.
Definition: rpmspec.h:108
const char * preInFile
Definition: rpmspec.h:221
struct TriggerFileEntry * next
Definition: rpmspec.h:32
char * script
Definition: rpmspec.h:28
rpmiob rpmiobNew(size_t len)
Create an I/O buffer.
Definition: rpmiob.c:44
const char * postUnFile
Definition: rpmspec.h:227
enum rpmRC_e rpmRC
RPM return codes.
char * rpmiobStr(rpmiob iob)
Return I/O buffer (as string).
Definition: rpmiob.c:113
Definition: rpmtag.h:503
This is the only module users of librpmbuild should need to include.
static const char * file
Definition: parseScript.c:60
static void * _free(const void *p)
Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
Definition: rpmiotypes.h:647
struct rpmiob_s * rpmiob
Definition: rpmiotypes.h:57
rpmRC parseRCPOT(Spec spec, Package pkg, const char *field, rpmTag tagN, rpmuint32_t index, rpmsenseFlags tagflags)
Parse dependency relations from spec file and/or autogenerated output buffer.
Definition: parseReqs.c:20
enum rpmParseState_e rpmParseState
int lineNum
Definition: rpmspec.h:134
static const char * name
Definition: parseScript.c:56
const char * verifyFile
Definition: rpmspec.h:233
struct rpmlua_s * rpmlua
Definition: rpmlua.h:53
#define _(Text)
Definition: system.h:30
The structure used to store values for a package.
Definition: rpmspec.h:207
const char * preUnFile
Definition: rpmspec.h:225
enum rpmTag_e rpmTag
Definition: rpmtag.h:471
const char * postTransFile
Definition: rpmspec.h:231
int rpmExpandNumeric(const char *arg)
Return macro expansion as a numeric value.
Definition: macro.c:3191
static struct poptOption optionsTable[]
Definition: parseScript.c:62
const char * preTransFile
Definition: rpmspec.h:229
const char * sanityCheckFile
Definition: rpmspec.h:235
int rpmlibNeedsFeature(Header h, const char *feature, const char *featureEVR)
Add rpmlib feature dependency.
Definition: reqprov.c:258