Main Page   Modules   Data Structures   File List   Data Fields   Globals   Related Pages  

build/parsePrep.c

Go to the documentation of this file.
00001 
00006 #include "system.h"
00007 
00008 #include <rpmio_internal.h>
00009 #include <rpmbuild.h>
00010 #include "debug.h"
00011 
00012 /*@access StringBuf @*/ /* compared with NULL */
00013 
00014 /* These have to be global to make up for stupid compilers */
00015     static int leaveDirs, skipDefaultAction;
00016     static int createDir, quietly;
00017 /*@observer@*/ /*@null@*/ static const char * dirName = NULL;
00018 /*@observer@*/ static struct poptOption optionsTable[] = {
00019             { NULL, 'a', POPT_ARG_STRING, NULL, 'a',    NULL, NULL},
00020             { NULL, 'b', POPT_ARG_STRING, NULL, 'b',    NULL, NULL},
00021             { NULL, 'c', 0, &createDir, 0,              NULL, NULL},
00022             { NULL, 'D', 0, &leaveDirs, 0,              NULL, NULL},
00023             { NULL, 'n', POPT_ARG_STRING, &dirName, 0,  NULL, NULL},
00024             { NULL, 'T', 0, &skipDefaultAction, 0,      NULL, NULL},
00025             { NULL, 'q', 0, &quietly, 0,                NULL, NULL},
00026             { 0, 0, 0, 0, 0,    NULL, NULL}
00027     };
00028 
00034 static int checkOwners(const char * urlfn)
00035         /*@*/
00036 {
00037     struct stat sb;
00038 
00039     if (Lstat(urlfn, &sb)) {
00040         rpmError(RPMERR_BADSPEC, _("Bad source: %s: %s\n"),
00041                 urlfn, strerror(errno));
00042         return RPMERR_BADSPEC;
00043     }
00044     if (!getUname(sb.st_uid) || !getGname(sb.st_gid)) {
00045         rpmError(RPMERR_BADSPEC, _("Bad owner/group: %s\n"), urlfn);
00046         return RPMERR_BADSPEC;
00047     }
00048 
00049     return 0;
00050 }
00051 
00062 /*@observer@*/ static char *doPatch(Spec spec, int c, int strip, const char *db,
00063                      int reverse, int removeEmpties)
00064         /*@modifies fileSystem @*/
00065 {
00066     const char *fn, *urlfn;
00067     static char buf[BUFSIZ];
00068     char args[BUFSIZ];
00069     struct Source *sp;
00070     rpmCompressedMagic compressed = COMPRESSED_NOT;
00071     int urltype;
00072 
00073     for (sp = spec->sources; sp != NULL; sp = sp->next) {
00074         if ((sp->flags & RPMBUILD_ISPATCH) && (sp->num == c)) {
00075             break;
00076         }
00077     }
00078     if (sp == NULL) {
00079         rpmError(RPMERR_BADSPEC, _("No patch number %d\n"), c);
00080         return NULL;
00081     }
00082 
00083     urlfn = rpmGetPath("%{_sourcedir}/", sp->source, NULL);
00084 
00085     args[0] = '\0';
00086     if (db) {
00087 #if HAVE_OLDPATCH_21 == 0
00088         strcat(args, "-b ");
00089 #endif
00090         strcat(args, "--suffix ");
00091         strcat(args, db);
00092     }
00093     if (reverse) {
00094         strcat(args, " -R");
00095     }
00096     if (removeEmpties) {
00097         strcat(args, " -E");
00098     }
00099 
00100     /* XXX On non-build parse's, file cannot be stat'd or read */
00101     if (!spec->force && (isCompressed(urlfn, &compressed) || checkOwners(urlfn))) {
00102         urlfn = _free(urlfn);
00103         return NULL;
00104     }
00105 
00106     fn = NULL;
00107     urltype = urlPath(urlfn, &fn);
00108     switch (urltype) {
00109     case URL_IS_HTTP:   /* XXX WRONG WRONG WRONG */
00110     case URL_IS_FTP:    /* XXX WRONG WRONG WRONG */
00111     case URL_IS_PATH:
00112     case URL_IS_UNKNOWN:
00113         break;
00114     case URL_IS_DASH:
00115         urlfn = _free(urlfn);
00116         return NULL;
00117         /*@notreached@*/ break;
00118     }
00119 
00120     if (compressed) {
00121         const char *zipper = rpmGetPath(
00122             (compressed == COMPRESSED_BZIP2 ? "%{_bzip2bin}" : "%{_gzipbin}"),
00123             NULL);
00124 
00125         sprintf(buf,
00126                 "echo \"Patch #%d (%s):\"\n"
00127                 "%s -d < %s | patch -p%d %s -s\n"
00128                 "STATUS=$?\n"
00129                 "if [ $STATUS -ne 0 ]; then\n"
00130                 "  exit $STATUS\n"
00131                 "fi",
00132                 c, /*@-unrecog@*/ (const char *) basename(fn), /*@=unrecog@*/
00133                 zipper,
00134                 fn, strip, args);
00135         zipper = _free(zipper);
00136     } else {
00137         sprintf(buf,
00138                 "echo \"Patch #%d (%s):\"\n"
00139                 "patch -p%d %s -s < %s", c, (const char *) basename(fn),
00140                 strip, args, fn);
00141     }
00142 
00143     urlfn = _free(urlfn);
00144     return buf;
00145 }
00146 
00154 /*@observer@*/ static const char *doUntar(Spec spec, int c, int quietly)
00155         /*@modifies fileSystem @*/
00156 {
00157     const char *fn, *urlfn;
00158     static char buf[BUFSIZ];
00159     char *taropts;
00160     char *t = NULL;
00161     struct Source *sp;
00162     rpmCompressedMagic compressed = COMPRESSED_NOT;
00163     int urltype;
00164 
00165     for (sp = spec->sources; sp != NULL; sp = sp->next) {
00166         if ((sp->flags & RPMBUILD_ISSOURCE) && (sp->num == c)) {
00167             break;
00168         }
00169     }
00170     if (sp == NULL) {
00171         rpmError(RPMERR_BADSPEC, _("No source number %d\n"), c);
00172         return NULL;
00173     }
00174 
00175     urlfn = rpmGetPath("%{_sourcedir}/", sp->source, NULL);
00176 
00177     taropts = ((rpmIsVerbose() && !quietly) ? "-xvvf" : "-xf");
00178 
00179 #ifdef AUTOFETCH_NOT    /* XXX don't expect this code to be enabled */
00180     /* XXX
00181      * XXX If nosource file doesn't exist, try to fetch from url.
00182      * XXX TODO: add a "--fetch" enabler.
00183      */
00184     if (sp->flags & RPMTAG_NOSOURCE && autofetchnosource) {
00185         struct stat st;
00186         int rc;
00187         if (Lstat(urlfn, &st) != 0 && errno == ENOENT &&
00188             urlIsUrl(sp->fullSource) != URL_IS_UNKNOWN) {
00189             if ((rc = urlGetFile(sp->fullSource, urlfn)) != 0) {
00190                 rpmError(RPMERR_BADFILENAME,
00191                         _("Couldn't download nosource %s: %s\n"),
00192                         sp->fullSource, ftpStrerror(rc));
00193                 return NULL;
00194             }
00195         }
00196     }
00197 #endif
00198 
00199     /* XXX On non-build parse's, file cannot be stat'd or read */
00200     if (!spec->force && (isCompressed(urlfn, &compressed) || checkOwners(urlfn))) {
00201         urlfn = _free(urlfn);
00202         return NULL;
00203     }
00204 
00205     fn = NULL;
00206     urltype = urlPath(urlfn, &fn);
00207     switch (urltype) {
00208     case URL_IS_HTTP:   /* XXX WRONG WRONG WRONG */
00209     case URL_IS_FTP:    /* XXX WRONG WRONG WRONG */
00210     case URL_IS_PATH:
00211     case URL_IS_UNKNOWN:
00212         break;
00213     case URL_IS_DASH:
00214         urlfn = _free(urlfn);
00215         return NULL;
00216         /*@notreached@*/ break;
00217     }
00218 
00219     if (compressed != COMPRESSED_NOT) {
00220         const char *zipper;
00221         int needtar = 1;
00222 
00223         switch (compressed) {
00224         case COMPRESSED_NOT:    /* XXX can't happen */
00225         case COMPRESSED_OTHER:
00226             t = "%{_gzipbin} -dc";
00227             break;
00228         case COMPRESSED_BZIP2:
00229             t = "%{_bzip2bin} -dc";
00230             break;
00231         case COMPRESSED_ZIP:
00232             t = "%{_unzipbin}";
00233             needtar = 0;
00234             break;
00235         }
00236         zipper = rpmGetPath(t, NULL);
00237         buf[0] = '\0';
00238         t = stpcpy(buf, zipper);
00239         zipper = _free(zipper);
00240         *t++ = ' ';
00241         t = stpcpy(t, fn);
00242         if (needtar)
00243             t = stpcpy( stpcpy( stpcpy(t, " | tar "), taropts), " -");
00244         t = stpcpy(t,
00245                 "\n"
00246                 "STATUS=$?\n"
00247                 "if [ $STATUS -ne 0 ]; then\n"
00248                 "  exit $STATUS\n"
00249                 "fi");
00250     } else {
00251         buf[0] = '\0';
00252         t = stpcpy( stpcpy(buf, "tar "), taropts);
00253         *t++ = ' ';
00254         t = stpcpy(t, fn);
00255     }
00256 
00257     urlfn = _free(urlfn);
00258     return buf;
00259 }
00260 
00268 static int doSetupMacro(Spec spec, char *line)
00269         /*@modifies spec->buildSubdir, spec->macros, spec->prep,
00270                 fileSystem @*/
00271 {
00272     char buf[BUFSIZ];
00273     StringBuf before;
00274     StringBuf after;
00275     poptContext optCon;
00276     int argc;
00277     const char ** argv;
00278     int arg;
00279     const char * optArg;
00280     int rc;
00281     int num;
00282 
00283     leaveDirs = skipDefaultAction = 0;
00284     createDir = quietly = 0;
00285     dirName = NULL;
00286 
00287     if ((rc = poptParseArgvString(line, &argc, &argv))) {
00288         rpmError(RPMERR_BADSPEC, _("Error parsing %%setup: %s\n"),
00289                         poptStrerror(rc));
00290         return RPMERR_BADSPEC;
00291     }
00292 
00293     before = newStringBuf();
00294     after = newStringBuf();
00295 
00296     optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
00297     while ((arg = poptGetNextOpt(optCon)) > 0) {
00298         optArg = poptGetOptArg(optCon);
00299 
00300         /* We only parse -a and -b here */
00301 
00302         if (parseNum(optArg, &num)) {
00303             rpmError(RPMERR_BADSPEC, _("line %d: Bad arg to %%setup: %s\n"),
00304                      spec->lineNum, (optArg ? optArg : "???"));
00305             before = freeStringBuf(before);
00306             after = freeStringBuf(after);
00307             optCon = poptFreeContext(optCon);
00308             argv = _free(argv);
00309             return RPMERR_BADSPEC;
00310         }
00311 
00312         {   const char *chptr = doUntar(spec, num, quietly);
00313             if (chptr == NULL)
00314                 return RPMERR_BADSPEC;
00315 
00316             appendLineStringBuf((arg == 'a' ? after : before), chptr);
00317         }
00318     }
00319 
00320     if (arg < -1) {
00321         rpmError(RPMERR_BADSPEC, _("line %d: Bad %%setup option %s: %s\n"),
00322                  spec->lineNum,
00323                  poptBadOption(optCon, POPT_BADOPTION_NOALIAS), 
00324                  poptStrerror(arg));
00325         before = freeStringBuf(before);
00326         after = freeStringBuf(after);
00327         optCon = poptFreeContext(optCon);
00328         argv = _free(argv);
00329         return RPMERR_BADSPEC;
00330     }
00331 
00332     if (dirName) {
00333         spec->buildSubdir = xstrdup(dirName);
00334     } else {
00335         const char *name, *version;
00336         (void) headerNVR(spec->packages->header, &name, &version, NULL);
00337         sprintf(buf, "%s-%s", name, version);
00338         spec->buildSubdir = xstrdup(buf);
00339     }
00340     addMacro(spec->macros, "buildsubdir", NULL, spec->buildSubdir, RMIL_SPEC);
00341     
00342     optCon = poptFreeContext(optCon);
00343     argv = _free(argv);
00344 
00345     /* cd to the build dir */
00346     {   const char * buildDirURL = rpmGenPath(spec->rootURL, "%{_builddir}", "");
00347         const char *buildDir;
00348 
00349         (void) urlPath(buildDirURL, &buildDir);
00350         sprintf(buf, "cd %s", buildDir);
00351         appendLineStringBuf(spec->prep, buf);
00352         buildDirURL = _free(buildDirURL);
00353     }
00354     
00355     /* delete any old sources */
00356     if (!leaveDirs) {
00357         sprintf(buf, "rm -rf %s", spec->buildSubdir);
00358         appendLineStringBuf(spec->prep, buf);
00359     }
00360 
00361     /* if necessary, create and cd into the proper dir */
00362     if (createDir) {
00363         sprintf(buf, MKDIR_P " %s\ncd %s",
00364                 spec->buildSubdir, spec->buildSubdir);
00365         appendLineStringBuf(spec->prep, buf);
00366     }
00367 
00368     /* do the default action */
00369    if (!createDir && !skipDefaultAction) {
00370         const char *chptr = doUntar(spec, 0, quietly);
00371         if (!chptr)
00372             return RPMERR_BADSPEC;
00373         appendLineStringBuf(spec->prep, chptr);
00374     }
00375 
00376     appendStringBuf(spec->prep, getStringBuf(before));
00377     before = freeStringBuf(before);
00378 
00379     if (!createDir) {
00380         sprintf(buf, "cd %s", spec->buildSubdir);
00381         appendLineStringBuf(spec->prep, buf);
00382     }
00383 
00384     if (createDir && !skipDefaultAction) {
00385         const char * chptr = doUntar(spec, 0, quietly);
00386         if (chptr == NULL)
00387             return RPMERR_BADSPEC;
00388         appendLineStringBuf(spec->prep, chptr);
00389     }
00390     
00391     appendStringBuf(spec->prep, getStringBuf(after));
00392     after = freeStringBuf(after);
00393 
00394     /* XXX FIXME: owner & group fixes were conditioned on !geteuid() */
00395     /* Fix the owner, group, and permissions of the setup build tree */
00396     {   /*@observer@*/ static const char *fixmacs[] =
00397                 { "%{_fixowner}", "%{_fixgroup}", "%{_fixperms}", NULL };
00398         const char ** fm;
00399 
00400         for (fm = fixmacs; *fm; fm++) {
00401             const char *fix;
00402             /*@-nullpass@*/
00403             fix = rpmExpand(*fm, " .", NULL);
00404             /*@=nullpass@*/
00405             if (fix && *fix != '%')
00406                 appendLineStringBuf(spec->prep, fix);
00407             fix = _free(fix);
00408         }
00409     }
00410     
00411     return 0;
00412 }
00413 
00420 static int doPatchMacro(Spec spec, char *line)
00421         /*@modifies spec->prep, fileSystem @*/
00422 {
00423     char *opt_b;
00424     int opt_P, opt_p, opt_R, opt_E;
00425     char *s;
00426     char buf[BUFSIZ], *bp;
00427     int patch_nums[1024];  /* XXX - we can only handle 1024 patches! */
00428     int patch_index, x;
00429 
00430     memset(patch_nums, 0, sizeof(patch_nums));
00431     opt_P = opt_p = opt_R = opt_E = 0;
00432     opt_b = NULL;
00433     patch_index = 0;
00434 
00435     if (! strchr(" \t\n", line[6])) {
00436         /* %patchN */
00437         sprintf(buf, "%%patch -P %s", line + 6);
00438     } else {
00439         strcpy(buf, line);
00440     }
00441     
00442     for (bp = buf; (s = strtok(bp, " \t\n")) != NULL;) {
00443         if (bp) {       /* remove 1st token (%patch) */
00444             bp = NULL;
00445             continue;
00446         }
00447         if (!strcmp(s, "-P")) {
00448             opt_P = 1;
00449         } else if (!strcmp(s, "-R")) {
00450             opt_R = 1;
00451         } else if (!strcmp(s, "-E")) {
00452             opt_E = 1;
00453         } else if (!strcmp(s, "-b")) {
00454             /* orig suffix */
00455             opt_b = strtok(NULL, " \t\n");
00456             if (! opt_b) {
00457                 rpmError(RPMERR_BADSPEC,
00458                         _("line %d: Need arg to %%patch -b: %s\n"),
00459                         spec->lineNum, spec->line);
00460                 return RPMERR_BADSPEC;
00461             }
00462         } else if (!strcmp(s, "-z")) {
00463             /* orig suffix */
00464             opt_b = strtok(NULL, " \t\n");
00465             if (! opt_b) {
00466                 rpmError(RPMERR_BADSPEC,
00467                         _("line %d: Need arg to %%patch -z: %s\n"),
00468                         spec->lineNum, spec->line);
00469                 return RPMERR_BADSPEC;
00470             }
00471         } else if (!strncmp(s, "-p", sizeof("-p")-1)) {
00472             /* unfortunately, we must support -pX */
00473             if (! strchr(" \t\n", s[2])) {
00474                 s = s + 2;
00475             } else {
00476                 s = strtok(NULL, " \t\n");
00477                 if (s == NULL) {
00478                     rpmError(RPMERR_BADSPEC,
00479                              _("line %d: Need arg to %%patch -p: %s\n"),
00480                              spec->lineNum, spec->line);
00481                     return RPMERR_BADSPEC;
00482                 }
00483             }
00484             if (parseNum(s, &opt_p)) {
00485                 rpmError(RPMERR_BADSPEC,
00486                         _("line %d: Bad arg to %%patch -p: %s\n"),
00487                         spec->lineNum, spec->line);
00488                 return RPMERR_BADSPEC;
00489             }
00490         } else {
00491             /* Must be a patch num */
00492             if (patch_index == 1024) {
00493                 rpmError(RPMERR_BADSPEC, _("Too many patches!\n"));
00494                 return RPMERR_BADSPEC;
00495             }
00496             if (parseNum(s, &(patch_nums[patch_index]))) {
00497                 rpmError(RPMERR_BADSPEC, _("line %d: Bad arg to %%patch: %s\n"),
00498                          spec->lineNum, spec->line);
00499                 return RPMERR_BADSPEC;
00500             }
00501             patch_index++;
00502         }
00503     }
00504 
00505     /* All args processed */
00506 
00507     if (! opt_P) {
00508         s = doPatch(spec, 0, opt_p, opt_b, opt_R, opt_E);
00509         if (s == NULL)
00510             return RPMERR_BADSPEC;
00511         appendLineStringBuf(spec->prep, s);
00512     }
00513 
00514     for (x = 0; x < patch_index; x++) {
00515         s = doPatch(spec, patch_nums[x], opt_p, opt_b, opt_R, opt_E);
00516         if (s == NULL)
00517             return RPMERR_BADSPEC;
00518         appendLineStringBuf(spec->prep, s);
00519     }
00520     
00521     return 0;
00522 }
00523 
00524 int parsePrep(Spec spec)
00525 {
00526     int nextPart, res, rc;
00527     StringBuf sb;
00528     char **lines, **saveLines;
00529 
00530     if (spec->prep != NULL) {
00531         rpmError(RPMERR_BADSPEC, _("line %d: second %%prep\n"), spec->lineNum);
00532         return RPMERR_BADSPEC;
00533     }
00534 
00535     spec->prep = newStringBuf();
00536 
00537     /* There are no options to %prep */
00538     if ((rc = readLine(spec, STRIP_NOTHING)) > 0) {
00539         return PART_NONE;
00540     }
00541     if (rc)
00542         return rc;
00543     
00544     sb = newStringBuf();
00545     
00546     while (! (nextPart = isPart(spec->line))) {
00547         /* Need to expand the macros inline.  That way we  */
00548         /* can give good line number information on error. */
00549         appendStringBuf(sb, spec->line);
00550         if ((rc = readLine(spec, STRIP_NOTHING)) > 0) {
00551             nextPart = PART_NONE;
00552             break;
00553         }
00554         if (rc)
00555             return rc;
00556     }
00557 
00558     saveLines = splitString(getStringBuf(sb), strlen(getStringBuf(sb)), '\n');
00559     /*@-usereleased@*/
00560     for (lines = saveLines; *lines; lines++) {
00561         res = 0;
00562         if (! strncmp(*lines, "%setup", sizeof("%setup")-1)) {
00563             res = doSetupMacro(spec, *lines);
00564         } else if (! strncmp(*lines, "%patch", sizeof("%patch")-1)) {
00565             res = doPatchMacro(spec, *lines);
00566         } else {
00567             appendLineStringBuf(spec->prep, *lines);
00568         }
00569         if (res && !spec->force) {
00570             freeSplitString(saveLines);
00571             sb = freeStringBuf(sb);
00572             return res;
00573         }
00574     }
00575     /*@=usereleased@*/
00576 
00577     freeSplitString(saveLines);
00578     sb = freeStringBuf(sb);
00579 
00580     return nextPart;
00581 }

Generated at Thu Sep 6 11:32:28 2001 for rpm by doxygen1.2.8.1 written by Dimitri van Heesch, © 1997-2001