rpm 5.3.7

build/parseScript.c

Go to the documentation of this file.
00001 
00006 #include "system.h"
00007 
00008 #include <rpmio.h>
00009 #include <rpmiotypes.h>
00010 #include <rpmlog.h>
00011 #define _RPMEVR_INTERNAL
00012 #include "rpmbuild.h"
00013 #include "debug.h"
00014 
00015 #include <rpmlua.h>
00016 
00017 /*@access poptContext @*/       /* compared with NULL */
00018 
00021 static rpmuint32_t addTriggerIndex(Package pkg, const char *file,
00022         const char *script, const char *prog)
00023         /*@modifies pkg->triggerFiles @*/
00024 {
00025     struct TriggerFileEntry *tfe;
00026     struct TriggerFileEntry *list = pkg->triggerFiles;
00027     struct TriggerFileEntry *last = NULL;
00028     rpmuint32_t index = 0;
00029 
00030     while (list) {
00031         last = list;
00032         list = list->next;
00033     }
00034 
00035     if (last)
00036         index = last->index + 1;
00037 
00038     tfe = xcalloc(1, sizeof(*tfe));
00039 
00040     tfe->fileName = (file) ? xstrdup(file) : NULL;
00041     tfe->script = (script && *script != '\0') ? xstrdup(script) : NULL;
00042     tfe->prog = xstrdup(prog);
00043     tfe->index = index;
00044     tfe->next = NULL;
00045 
00046     if (last)
00047         last->next = tfe;
00048     else
00049         pkg->triggerFiles = tfe;
00050 
00051     return index;
00052 }
00053 
00054 /* these have to be global because of stupid compilers */
00055 /*@unchecked@*/
00056     /*@observer@*/ /*@null@*/ static const char *name = NULL;
00057 /*@unchecked@*/
00058     /*@observer@*/ /*@null@*/ static const char *prog = NULL;
00059 /*@unchecked@*/
00060     /*@observer@*/ /*@null@*/ static const char *file = NULL;
00061 /*@unchecked@*/
00062     static struct poptOption optionsTable[] = {
00063         { NULL, 'p', POPT_ARG_STRING, &prog, 'p',       NULL, NULL},
00064         { NULL, 'n', POPT_ARG_STRING, &name, 'n',       NULL, NULL},
00065         { NULL, 'f', POPT_ARG_STRING, &file, 'f',       NULL, NULL},
00066         { 0, 0, 0, 0, 0,        NULL, NULL}
00067     };
00068 
00069 /* %trigger is a strange combination of %pre and Requires: behavior */
00070 /* We can handle it by parsing the args before "--" in parseScript. */
00071 /* We then pass the remaining arguments to parseRCPOT, along with   */
00072 /* an index we just determined.                                     */
00073 
00074 int parseScript(Spec spec, int parsePart)
00075 {
00076     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
00077     int xx;
00078 
00079     /* There are a few options to scripts: */
00080     /*  <pkg>                              */
00081     /*  -n <pkg>                           */
00082     /*  -p <sh>                            */
00083     /*  -p "<sh> <args>..."                */
00084     /*  -f <file>                          */
00085 
00086     char *p;
00087     const char **progArgv = NULL;
00088     int progArgc;
00089     char *partname = NULL;
00090     rpmTag reqtag = 0;
00091     rpmTag tag = 0;
00092     rpmsenseFlags tagflags = 0;
00093     rpmTag progtag = 0;
00094     int flag = PART_SUBNAME;
00095     Package pkg;
00096     rpmiob iob = NULL;
00097     rpmParseState nextPart;
00098     char reqargs[BUFSIZ];
00099 
00100     int argc;
00101     int arg;
00102     const char **argv = NULL;
00103     poptContext optCon = NULL;
00104     rpmRC rc;
00105     
00106     reqargs[0] = '\0';
00107     /*@-mods@*/
00108     name = NULL;
00109     prog = "/bin/sh";
00110     file = NULL;
00111     /*@=mods@*/
00112     
00113     switch (parsePart) {
00114       case PART_PRE:
00115         tag = RPMTAG_PREIN;
00116         tagflags = RPMSENSE_SCRIPT_PRE;
00117         progtag = RPMTAG_PREINPROG;
00118         partname = "%pre";
00119         break;
00120       case PART_POST:
00121         tag = RPMTAG_POSTIN;
00122         tagflags = RPMSENSE_SCRIPT_POST;
00123         progtag = RPMTAG_POSTINPROG;
00124         partname = "%post";
00125         break;
00126       case PART_PREUN:
00127         tag = RPMTAG_PREUN;
00128         tagflags = RPMSENSE_SCRIPT_PREUN;
00129         progtag = RPMTAG_PREUNPROG;
00130         partname = "%preun";
00131         break;
00132       case PART_POSTUN:
00133         tag = RPMTAG_POSTUN;
00134         tagflags = RPMSENSE_SCRIPT_POSTUN;
00135         progtag = RPMTAG_POSTUNPROG;
00136         partname = "%postun";
00137         break;
00138       case PART_PRETRANS:
00139         tag = RPMTAG_PRETRANS;
00140         tagflags = 0;
00141         progtag = RPMTAG_PRETRANSPROG;
00142         partname = "%pretrans";
00143         break;
00144       case PART_POSTTRANS:
00145         tag = RPMTAG_POSTTRANS;
00146         tagflags = 0;
00147         progtag = RPMTAG_POSTTRANSPROG;
00148         partname = "%posttrans";
00149         break;
00150       case PART_VERIFYSCRIPT:
00151         tag = RPMTAG_VERIFYSCRIPT;
00152         tagflags = RPMSENSE_SCRIPT_VERIFY;
00153         progtag = RPMTAG_VERIFYSCRIPTPROG;
00154         partname = "%verifyscript";
00155         break;
00156       case PART_TRIGGERPREIN:
00157         tag = RPMTAG_TRIGGERSCRIPTS;
00158         tagflags = 0;
00159         reqtag = RPMTAG_TRIGGERPREIN;
00160         progtag = RPMTAG_TRIGGERSCRIPTPROG;
00161         partname = "%triggerprein";
00162         break;
00163       case PART_TRIGGERIN:
00164         tag = RPMTAG_TRIGGERSCRIPTS;
00165         tagflags = 0;
00166         reqtag = RPMTAG_TRIGGERIN;
00167         progtag = RPMTAG_TRIGGERSCRIPTPROG;
00168         partname = "%triggerin";
00169         break;
00170       case PART_TRIGGERUN:
00171         tag = RPMTAG_TRIGGERSCRIPTS;
00172         tagflags = 0;
00173         reqtag = RPMTAG_TRIGGERUN;
00174         progtag = RPMTAG_TRIGGERSCRIPTPROG;
00175         partname = "%triggerun";
00176         break;
00177       case PART_TRIGGERPOSTUN:
00178         tag = RPMTAG_TRIGGERSCRIPTS;
00179         tagflags = 0;
00180         reqtag = RPMTAG_TRIGGERPOSTUN;
00181         progtag = RPMTAG_TRIGGERSCRIPTPROG;
00182         partname = "%triggerpostun";
00183         break;
00184       /* support "%sanitycheck" script/section */
00185       case PART_SANITYCHECK:
00186         tag = RPMTAG_SANITYCHECK;
00187         tagflags = RPMSENSE_SCRIPT_SANITYCHECK;
00188         progtag = RPMTAG_SANITYCHECKPROG;
00189         partname = "%sanitycheck";
00190         break;
00191     }
00192 
00193     if (tag == RPMTAG_TRIGGERSCRIPTS) {
00194         /* break line into two */
00195         p = strstr(spec->line, "--");
00196         if (!p) {
00197             rpmlog(RPMLOG_ERR, _("line %d: triggers must have --: %s\n"),
00198                      spec->lineNum, spec->line);
00199             return RPMRC_FAIL;
00200         }
00201 
00202         *p = '\0';
00203         strcpy(reqargs, p + 2);
00204     }
00205     
00206     if ((rc = poptParseArgvString(spec->line, &argc, &argv))) {
00207         rpmlog(RPMLOG_ERR, _("line %d: Error parsing %s: %s\n"),
00208                  spec->lineNum, partname, poptStrerror(rc));
00209         return RPMRC_FAIL;
00210     }
00211     
00212     optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
00213     while ((arg = poptGetNextOpt(optCon)) > 0) {
00214         switch (arg) {
00215         case 'p':
00216             if (prog[0] == '<') {
00217                 const char * s = prog;
00218                 while (s && s[1] && s[1] != '>')
00219                     s++;
00220                 if (s[1] != '>') {
00221                     rpmlog(RPMLOG_ERR,
00222                              _("line %d: embedded interpreter token must end "
00223                              "with \'>\': %s\n"), spec->lineNum, prog);
00224                     rc = RPMRC_FAIL;
00225                     goto exit;
00226                 }
00227             } else if (prog[0] == '%') {
00228                 /* XXX check well-formed macro? */
00229             } else if (prog[0] != '/') {
00230                 rpmlog(RPMLOG_ERR,
00231                          _("line %d: script program must begin "
00232                          "with \'/\': %s\n"), spec->lineNum, prog);
00233                 rc = RPMRC_FAIL;
00234                 goto exit;
00235             }
00236             /*@switchbreak@*/ break;
00237         case 'n':
00238             flag = PART_NAME;
00239             /*@switchbreak@*/ break;
00240         }
00241     }
00242     
00243     if (arg < -1) {
00244         rpmlog(RPMLOG_ERR, _("line %d: Bad option %s: %s\n"),
00245                  spec->lineNum,
00246                  poptBadOption(optCon, POPT_BADOPTION_NOALIAS), 
00247                  spec->line);
00248         rc = RPMRC_FAIL;
00249         goto exit;
00250     }
00251 
00252     if (poptPeekArg(optCon)) {
00253         /*@-mods@*/
00254         if (name == NULL)
00255             name = poptGetArg(optCon);
00256         /*@=mods@*/
00257         if (poptPeekArg(optCon)) {
00258             rpmlog(RPMLOG_ERR, _("line %d: Too many names: %s\n"),
00259                      spec->lineNum,
00260                      spec->line);
00261             rc = RPMRC_FAIL;
00262             goto exit;
00263         }
00264     }
00265     
00266     if (lookupPackage(spec, name, flag, &pkg) != RPMRC_OK) {
00267         rpmlog(RPMLOG_ERR, _("line %d: Package does not exist: %s\n"),
00268                  spec->lineNum, spec->line);
00269         rc = RPMRC_FAIL;
00270         goto exit;
00271     }
00272 
00273     if (tag != RPMTAG_TRIGGERSCRIPTS) {
00274         if (headerIsEntry(pkg->header, progtag)) {
00275             rpmlog(RPMLOG_ERR, _("line %d: Second %s\n"),
00276                      spec->lineNum, partname);
00277             rc = RPMRC_FAIL;
00278             goto exit;
00279         }
00280     }
00281 
00282     if ((rc = poptParseArgvString(prog, &progArgc, &progArgv))) {
00283         rpmlog(RPMLOG_ERR, _("line %d: Error parsing %s: %s\n"),
00284                  spec->lineNum, partname, poptStrerror(rc));
00285         rc = RPMRC_FAIL;
00286         goto exit;
00287     }
00288 
00289     iob = rpmiobNew(0);
00290     if ((rc = readLine(spec, STRIP_NOTHING)) > 0) {
00291         nextPart = PART_NONE;
00292     } else {
00293         if (rc)
00294             goto exit;
00295         while ((nextPart = isPart(spec)) == PART_NONE) {
00296             iob = rpmiobAppend(iob, spec->line, 0);
00297             if ((rc = readLine(spec, STRIP_NOTHING)) > 0) {
00298                 nextPart = PART_NONE;
00299                 break;
00300             }
00301             if (rc)
00302                 goto exit;
00303         }
00304     }
00305     iob = rpmiobRTrim(iob);
00306     p = rpmiobStr(iob);
00307 
00308 #ifdef WITH_LUA
00309     if (!strcmp(progArgv[0], "<lua>")) {
00310         rpmlua lua = NULL; /* Global state. */
00311         if (rpmluaCheckScript(lua, p, partname) != RPMRC_OK) {
00312             rc = RPMRC_FAIL;
00313             goto exit;
00314         }
00315         (void) rpmlibNeedsFeature(pkg->header,
00316                                   "BuiltinLuaScripts", "4.2.2-1");
00317     } else
00318 #endif
00319 #ifdef WITH_AUGEAS
00320     if (!strcmp(progArgv[0], "<augeas>")) {
00321         (void) rpmlibNeedsFeature(pkg->header,
00322                                   "BuiltinAugeasScripts", "5.3-1");
00323     } else
00324 #endif
00325 #ifdef WITH_FICL
00326     if (!strcmp(progArgv[0], "<ficl>")) {
00327         (void) rpmlibNeedsFeature(pkg->header,
00328                                   "BuiltinFiclScripts", "5.2-1");
00329     } else
00330 #endif
00331 #ifdef WITH_GPSEE
00332     if (!strcmp(progArgv[0], "<js>")) {
00333         (void) rpmlibNeedsFeature(pkg->header,
00334                                   "BuiltinJavaScript", "5.2-1");
00335     } else
00336 #endif
00337 #ifdef WITH_PERLEMBED
00338     if (!strcmp(progArgv[0], "<perl>")) {
00339         (void) rpmlibNeedsFeature(pkg->header,
00340                                   "BuiltinPerlScripts", "5.2-1");
00341     } else
00342 #endif
00343 #ifdef WITH_PYTHONEMBED
00344     if (!strcmp(progArgv[0], "<python>")) {
00345         (void) rpmlibNeedsFeature(pkg->header,
00346                                   "BuiltinPythonScripts", "5.2-1");
00347     } else
00348 #endif
00349 #ifdef WITH_RUBYEMBED
00350     if (!strcmp(progArgv[0], "<ruby>")) {
00351         (void) rpmlibNeedsFeature(pkg->header,
00352                                   "BuiltinRubyScripts", "5.2-1");
00353     } else
00354 #endif
00355 #ifdef WITH_SEMANAGE
00356     if (!strcmp(progArgv[0], "<spook>")) {
00357         (void) rpmlibNeedsFeature(pkg->header,
00358                                   "BuiltinSpookScripts", "5.3-1");
00359     } else
00360 #endif
00361 #ifdef WITH_SQLITE
00362     if (!strcmp(progArgv[0], "<sql>")) {
00363         (void) rpmlibNeedsFeature(pkg->header,
00364                                   "BuiltinSqlScripts", "5.3-1");
00365     } else
00366 #endif
00367 #ifdef WITH_SQUIRREL
00368     if (!strcmp(progArgv[0], "<squirrel>")) {
00369         (void) rpmlibNeedsFeature(pkg->header,
00370                                   "BuiltinSquirrelScripts", "5.2-1");
00371     } else
00372 #endif
00373 #ifdef WITH_TCL
00374     if (!strcmp(progArgv[0], "<tcl>")) {
00375         (void) rpmlibNeedsFeature(pkg->header,
00376                                   "BuiltinTclScripts", "5.2-1");
00377     } else
00378 #endif
00379     if (progArgv[0][0] == '<') {
00380         rpmlog(RPMLOG_ERR,
00381                  _("line %d: unsupported internal script: %s\n"),
00382                  spec->lineNum, progArgv[0]);
00383         rc = RPMRC_FAIL;
00384         goto exit;
00385     } else
00386     if (!(rpmExpandNumeric("%{?_disable_shell_interpreter_deps}")
00387      && !strcmp(progArgv[0], "/bin/sh")))
00388     {
00389 
00390         (void) addReqProv(spec, pkg->header, RPMTAG_REQUIRENAME,
00391                 progArgv[0], NULL, (tagflags | RPMSENSE_INTERP), 0);
00392     }
00393 
00394     /* Trigger script insertion is always delayed in order to */
00395     /* get the index right.                                   */
00396     if (tag == RPMTAG_TRIGGERSCRIPTS) {
00397         /* Add file/index/prog triple to the trigger file list */
00398         rpmuint32_t index = addTriggerIndex(pkg, file, p, progArgv[0]);
00399 
00400         /* Generate the trigger tags */
00401         if ((rc = parseRCPOT(spec, pkg, reqargs, reqtag, index, tagflags)))
00402             goto exit;
00403     } else {
00404         if (progArgc == 1) {
00405             he->tag = progtag;
00406             he->t = RPM_STRING_TYPE;
00407             he->p.str = *progArgv;
00408             he->c = progArgc;
00409             xx = headerPut(pkg->header, he, 0);
00410         } else {
00411             (void) rpmlibNeedsFeature(pkg->header,
00412                         "ScriptletInterpreterArgs", "4.0.3-1");
00413             he->tag = progtag;
00414             he->t = RPM_STRING_ARRAY_TYPE;
00415             he->p.argv = progArgv;
00416             he->c = progArgc;
00417             xx = headerPut(pkg->header, he, 0);
00418         }
00419 
00420         if (*p != '\0') {
00421             he->tag = tag;
00422             he->t = RPM_STRING_TYPE;
00423             he->p.str = p;
00424             he->c = 1;
00425             xx = headerPut(pkg->header, he, 0);
00426         }
00427 
00428         if (file) {
00429             switch (parsePart) {
00430               case PART_PRE:
00431                 pkg->preInFile = xstrdup(file);
00432                 break;
00433               case PART_POST:
00434                 pkg->postInFile = xstrdup(file);
00435                 break;
00436               case PART_PREUN:
00437                 pkg->preUnFile = xstrdup(file);
00438                 break;
00439               case PART_POSTUN:
00440                 pkg->postUnFile = xstrdup(file);
00441                 break;
00442               case PART_PRETRANS:
00443                 pkg->preTransFile = xstrdup(file);
00444                 break;
00445               case PART_POSTTRANS:
00446                 pkg->postTransFile = xstrdup(file);
00447                 break;
00448               case PART_VERIFYSCRIPT:
00449                 pkg->verifyFile = xstrdup(file);
00450                 break;
00451               case PART_SANITYCHECK:
00452                 pkg->sanityCheckFile = xstrdup(file);
00453                 break;
00454             }
00455         }
00456     }
00457     rc = (rpmRC) nextPart;
00458     
00459 exit:
00460     iob = rpmiobFree(iob);
00461     progArgv = _free(progArgv);
00462     argv = _free(argv);
00463     optCon = poptFreeContext(optCon);
00464     
00465     return rc;
00466 }