- Main Page
- Related Pages
- Modules
- Data Structures
- Files

# build/parseScript.c

Go to the documentation of this file.

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