00001
00006 #include "system.h"
00007
00008 #include <rpmio_internal.h>
00009 #include <rpmbuild.h>
00010 #include "debug.h"
00011
00012
00013
00014
00015
00016 static int leaveDirs, skipDefaultAction;
00017
00018 static int createDir, quietly;
00019
00020 static const char * dirName = NULL;
00021
00022 static struct poptOption optionsTable[] = {
00023 { NULL, 'a', POPT_ARG_STRING, NULL, 'a', NULL, NULL},
00024 { NULL, 'b', POPT_ARG_STRING, NULL, 'b', NULL, NULL},
00025 { NULL, 'c', 0, &createDir, 0, NULL, NULL},
00026 { NULL, 'D', 0, &leaveDirs, 0, NULL, NULL},
00027 { NULL, 'n', POPT_ARG_STRING, &dirName, 0, NULL, NULL},
00028 { NULL, 'T', 0, &skipDefaultAction, 0, NULL, NULL},
00029 { NULL, 'q', 0, &quietly, 0, NULL, NULL},
00030 { 0, 0, 0, 0, 0, NULL, NULL}
00031 };
00032
00038 static int checkOwners(const char * urlfn)
00039
00040
00041 {
00042 struct stat sb;
00043
00044 if (Lstat(urlfn, &sb)) {
00045 rpmError(RPMERR_BADSPEC, _("Bad source: %s: %s\n"),
00046 urlfn, strerror(errno));
00047 return RPMERR_BADSPEC;
00048 }
00049 if (!getUname(sb.st_uid) || !getGname(sb.st_gid)) {
00050 rpmError(RPMERR_BADSPEC, _("Bad owner/group: %s\n"), urlfn);
00051 return RPMERR_BADSPEC;
00052 }
00053
00054 return 0;
00055 }
00056
00068
00069
00070 static char *doPatch(Spec spec, int c, int strip, const char *db,
00071 int reverse, int removeEmpties, int fuzz)
00072
00073
00074 {
00075 const char *fn, *urlfn;
00076 static char buf[BUFSIZ];
00077 char args[BUFSIZ], *t = args;
00078 struct Source *sp;
00079 rpmCompressedMagic compressed = COMPRESSED_NOT;
00080 int urltype;
00081
00082 for (sp = spec->sources; sp != NULL; sp = sp->next) {
00083 if ((sp->flags & RPMBUILD_ISPATCH) && (sp->num == c)) {
00084 break;
00085 }
00086 }
00087 if (sp == NULL) {
00088 rpmError(RPMERR_BADSPEC, _("No patch number %d\n"), c);
00089 return NULL;
00090 }
00091
00092 urlfn = rpmGetPath("%{_sourcedir}/", sp->source, NULL);
00093
00094 *t = '\0';
00095 if (db) {
00096 #if HAVE_OLDPATCH_21 == 0
00097 t = stpcpy(t, "-b ");
00098 #endif
00099 t = stpcpy( stpcpy(t, "--suffix "), db);
00100 }
00101 if (fuzz >= 0) {
00102 t = stpcpy(t, " --fuzz=");
00103 sprintf(t, "%d", fuzz);
00104 t += strlen(t);
00105 }
00106 if (reverse)
00107 t = stpcpy(t, " -R");
00108 if (removeEmpties)
00109 t = stpcpy(t, " -E");
00110
00111
00112 if (!spec->force && (isCompressed(urlfn, &compressed) || checkOwners(urlfn))) {
00113 urlfn = _free(urlfn);
00114 return NULL;
00115 }
00116
00117 fn = NULL;
00118 urltype = urlPath(urlfn, &fn);
00119 switch (urltype) {
00120 case URL_IS_HTTPS:
00121 case URL_IS_HTTP:
00122 case URL_IS_FTP:
00123 case URL_IS_HKP:
00124 case URL_IS_PATH:
00125 case URL_IS_UNKNOWN:
00126 break;
00127 case URL_IS_DASH:
00128 urlfn = _free(urlfn);
00129 return NULL;
00130 break;
00131 }
00132
00133 if (compressed) {
00134 const char *zipper = NULL;
00135 const char *zipbin;
00136 switch (compressed) {
00137 case COMPRESSED_OTHER:
00138 zipbin = "%{_gzipbin}";
00139 break;
00140 case COMPRESSED_BZIP2:
00141 zipbin = "%{_bzip2bin}";
00142 break;
00143 case COMPRESSED_LZMA:
00144 zipbin = "%{__lzma}";
00145 break;
00146 case COMPRESSED_XZ:
00147 zipbin = "%{__xz}";
00148 break;
00149 default:
00150 return NULL;
00151 break;
00152 }
00153
00154 zipper = rpmGetPath(zipbin, NULL);
00155
00156 sprintf(buf,
00157 "echo \"Patch #%d (%s):\"\n"
00158 "%s -d < '%s' | patch -p%d %s -s\n"
00159 "STATUS=$?\n"
00160 "if [ $STATUS -ne 0 ]; then\n"
00161 " exit $STATUS\n"
00162 "fi",
00163 c, (const char *) basename(fn),
00164 zipper,
00165 fn, strip, args);
00166 zipper = _free(zipper);
00167 } else {
00168 sprintf(buf,
00169 "echo \"Patch #%d (%s):\"\n"
00170 "patch -p%d %s -s < '%s'", c, (const char *) basename(fn),
00171 strip, args, fn);
00172 }
00173
00174 urlfn = _free(urlfn);
00175 return buf;
00176 }
00177
00178
00186
00187 static const char *doUntar(Spec spec, int c, int quietly)
00188
00189
00190 {
00191 const char *fn, *urlfn;
00192 static char buf[BUFSIZ];
00193 char *taropts;
00194 char *t = NULL;
00195 struct Source *sp;
00196 rpmCompressedMagic compressed = COMPRESSED_NOT;
00197 int urltype;
00198
00199 for (sp = spec->sources; sp != NULL; sp = sp->next) {
00200 if ((sp->flags & RPMBUILD_ISSOURCE) && (sp->num == c)) {
00201 break;
00202 }
00203 }
00204 if (sp == NULL) {
00205 rpmError(RPMERR_BADSPEC, _("No source number %d\n"), c);
00206 return NULL;
00207 }
00208
00209 urlfn = rpmGetPath("%{_sourcedir}/", sp->source, NULL);
00210
00211
00212 taropts = ((rpmIsVerbose() && !quietly) ? "-xvvf" : "-xf");
00213
00214
00215 #ifdef AUTOFETCH_NOT
00216
00217
00218
00219
00220 if (sp->flags & RPMTAG_NOSOURCE && autofetchnosource) {
00221 struct stat st;
00222 int rc;
00223 if (Lstat(urlfn, &st) != 0 && errno == ENOENT &&
00224 urlIsUrl(sp->fullSource) != URL_IS_UNKNOWN) {
00225 if ((rc = urlGetFile(sp->fullSource, urlfn)) != 0) {
00226 rpmError(RPMERR_BADFILENAME,
00227 _("Couldn't download nosource %s: %s\n"),
00228 sp->fullSource, ftpStrerror(rc));
00229 return NULL;
00230 }
00231 }
00232 }
00233 #endif
00234
00235
00236 if (!spec->force && (isCompressed(urlfn, &compressed) || checkOwners(urlfn))) {
00237 urlfn = _free(urlfn);
00238 return NULL;
00239 }
00240
00241 fn = NULL;
00242 urltype = urlPath(urlfn, &fn);
00243 switch (urltype) {
00244 case URL_IS_HTTPS:
00245 case URL_IS_HTTP:
00246 case URL_IS_FTP:
00247 case URL_IS_HKP:
00248 case URL_IS_PATH:
00249 case URL_IS_UNKNOWN:
00250 break;
00251 case URL_IS_DASH:
00252 urlfn = _free(urlfn);
00253 return NULL;
00254 break;
00255 }
00256
00257 if (compressed != COMPRESSED_NOT) {
00258 const char *zipper;
00259 int needtar = 1;
00260
00261 switch (compressed) {
00262 case COMPRESSED_NOT:
00263 case COMPRESSED_OTHER:
00264 t = "%{_gzipbin} -dc";
00265 break;
00266 case COMPRESSED_BZIP2:
00267 t = "%{_bzip2bin} -dc";
00268 break;
00269 case COMPRESSED_ZIP:
00270 if (rpmIsVerbose() && !quietly)
00271 t = "%{_unzipbin}";
00272 else
00273 t = "%{_unzipbin} -qq";
00274 needtar = 0;
00275 break;
00276 case COMPRESSED_LZMA:
00277 t = "%{__lzma} -dc";
00278 break;
00279 case COMPRESSED_XZ:
00280 t = "%{__xz} -dc";
00281 break;
00282 }
00283 zipper = rpmGetPath(t, NULL);
00284 buf[0] = '\0';
00285 t = stpcpy(buf, zipper);
00286 zipper = _free(zipper);
00287 t = stpcpy(t, " '");
00288 t = stpcpy(t, fn);
00289 t = stpcpy(t, "'");
00290 if (needtar)
00291 t = stpcpy( stpcpy( stpcpy(t, " | tar "), taropts), " -");
00292 t = stpcpy(t,
00293 "\n"
00294 "STATUS=$?\n"
00295 "if [ $STATUS -ne 0 ]; then\n"
00296 " exit $STATUS\n"
00297 "fi");
00298 } else {
00299 buf[0] = '\0';
00300 t = stpcpy( stpcpy(buf, "tar "), taropts);
00301 *t++ = ' ';
00302 t = stpcpy(t, fn);
00303 }
00304
00305 urlfn = _free(urlfn);
00306 return buf;
00307 }
00308
00309
00317 static int doSetupMacro(Spec spec, char *line)
00318
00319
00320
00321 {
00322 char buf[BUFSIZ];
00323 StringBuf before;
00324 StringBuf after;
00325 poptContext optCon;
00326 int argc;
00327 const char ** argv;
00328 int arg;
00329 const char * optArg;
00330 int rc;
00331 int num;
00332
00333
00334 leaveDirs = skipDefaultAction = 0;
00335 createDir = quietly = 0;
00336 dirName = NULL;
00337
00338
00339 if ((rc = poptParseArgvString(line, &argc, &argv))) {
00340 rpmError(RPMERR_BADSPEC, _("Error parsing %%setup: %s\n"),
00341 poptStrerror(rc));
00342 return RPMERR_BADSPEC;
00343 }
00344
00345 before = newStringBuf();
00346 after = newStringBuf();
00347
00348 optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
00349 while ((arg = poptGetNextOpt(optCon)) > 0) {
00350 optArg = poptGetOptArg(optCon);
00351
00352
00353
00354 if (parseNum(optArg, &num)) {
00355 rpmError(RPMERR_BADSPEC, _("line %d: Bad arg to %%setup: %s\n"),
00356 spec->lineNum, (optArg ? optArg : "???"));
00357 before = freeStringBuf(before);
00358 after = freeStringBuf(after);
00359 optCon = poptFreeContext(optCon);
00360 argv = _free(argv);
00361 return RPMERR_BADSPEC;
00362 }
00363
00364 { const char *chptr = doUntar(spec, num, quietly);
00365 if (chptr == NULL)
00366 return RPMERR_BADSPEC;
00367
00368 appendLineStringBuf((arg == 'a' ? after : before), chptr);
00369 }
00370 }
00371
00372 if (arg < -1) {
00373 rpmError(RPMERR_BADSPEC, _("line %d: Bad %%setup option %s: %s\n"),
00374 spec->lineNum,
00375 poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
00376 poptStrerror(arg));
00377 before = freeStringBuf(before);
00378 after = freeStringBuf(after);
00379 optCon = poptFreeContext(optCon);
00380 argv = _free(argv);
00381 return RPMERR_BADSPEC;
00382 }
00383
00384 if (dirName) {
00385 spec->buildSubdir = xstrdup(dirName);
00386 } else {
00387 const char *name, *version;
00388 (void) headerNVR(spec->packages->header, &name, &version, NULL);
00389 sprintf(buf, "%s-%s", name, version);
00390 spec->buildSubdir = xstrdup(buf);
00391 }
00392 addMacro(spec->macros, "buildsubdir", NULL, spec->buildSubdir, RMIL_SPEC);
00393
00394 optCon = poptFreeContext(optCon);
00395 argv = _free(argv);
00396
00397
00398 { const char * buildDirURL = rpmGenPath(spec->rootURL, "%{_builddir}", "");
00399 const char *buildDir;
00400
00401 (void) urlPath(buildDirURL, &buildDir);
00402 sprintf(buf, "cd '%s'", buildDir);
00403 appendLineStringBuf(spec->prep, buf);
00404 buildDirURL = _free(buildDirURL);
00405 }
00406
00407
00408 if (!leaveDirs) {
00409 sprintf(buf, "rm -rf '%s'", spec->buildSubdir);
00410 appendLineStringBuf(spec->prep, buf);
00411 }
00412
00413
00414 if (createDir) {
00415 sprintf(buf, MKDIR_P " %s\ncd '%s'",
00416 spec->buildSubdir, spec->buildSubdir);
00417 appendLineStringBuf(spec->prep, buf);
00418 }
00419
00420
00421 if (!createDir && !skipDefaultAction) {
00422 const char *chptr = doUntar(spec, 0, quietly);
00423 if (!chptr)
00424 return RPMERR_BADSPEC;
00425 appendLineStringBuf(spec->prep, chptr);
00426 }
00427
00428 appendStringBuf(spec->prep, getStringBuf(before));
00429 before = freeStringBuf(before);
00430
00431 if (!createDir) {
00432 sprintf(buf, "cd '%s'", spec->buildSubdir);
00433 appendLineStringBuf(spec->prep, buf);
00434 }
00435
00436 if (createDir && !skipDefaultAction) {
00437 const char * chptr = doUntar(spec, 0, quietly);
00438 if (chptr == NULL)
00439 return RPMERR_BADSPEC;
00440 appendLineStringBuf(spec->prep, chptr);
00441 }
00442
00443 appendStringBuf(spec->prep, getStringBuf(after));
00444 after = freeStringBuf(after);
00445
00446
00447
00448 { static const char *fixmacs[] =
00449 { "%{_fixowner}", "%{_fixgroup}", "%{_fixperms}", NULL };
00450 const char ** fm;
00451
00452 for (fm = fixmacs; *fm; fm++) {
00453 const char *fix;
00454
00455 fix = rpmExpand(*fm, " .", NULL);
00456 if (fix && *fix != '%')
00457 appendLineStringBuf(spec->prep, fix);
00458 fix = _free(fix);
00459
00460 }
00461 }
00462
00463 return 0;
00464 }
00465
00472
00473 static int doPatchMacro(Spec spec, char *line)
00474
00475
00476
00477
00478 {
00479 char *opt_b;
00480 int opt_P, opt_p, opt_R, opt_E, opt_F;
00481 char *s;
00482 char buf[BUFSIZ], *bp;
00483 int patch_nums[1024];
00484 int patch_index, x;
00485
00486 memset(patch_nums, 0, sizeof(patch_nums));
00487 opt_P = opt_p = opt_R = opt_E = 0;
00488 opt_F = rpmExpandNumeric("%{_default_patch_fuzz}");
00489 opt_b = NULL;
00490 patch_index = 0;
00491
00492 if (! strchr(" \t\n", line[6])) {
00493
00494 sprintf(buf, "%%patch -P %s", line + 6);
00495 } else {
00496 strcpy(buf, line);
00497 }
00498
00499
00500 for (bp = buf; (s = strtok(bp, " \t\n")) != NULL;) {
00501 if (bp) {
00502 bp = NULL;
00503 continue;
00504 }
00505 if (!strcmp(s, "-P")) {
00506 opt_P = 1;
00507 } else if (!strcmp(s, "-R")) {
00508 opt_R = 1;
00509 } else if (!strcmp(s, "-E")) {
00510 opt_E = 1;
00511 } else if (!strcmp(s, "-b")) {
00512
00513 opt_b = strtok(NULL, " \t\n");
00514 if (! opt_b) {
00515 rpmError(RPMERR_BADSPEC,
00516 _("line %d: Need arg to %%patch -b: %s\n"),
00517 spec->lineNum, spec->line);
00518 return RPMERR_BADSPEC;
00519 }
00520 } else if (!strcmp(s, "-z")) {
00521
00522 opt_b = strtok(NULL, " \t\n");
00523 if (! opt_b) {
00524 rpmError(RPMERR_BADSPEC,
00525 _("line %d: Need arg to %%patch -z: %s\n"),
00526 spec->lineNum, spec->line);
00527 return RPMERR_BADSPEC;
00528 }
00529 } else if (!strncmp(s, "-F", strlen("-F"))) {
00530
00531 const char * fnum = NULL;
00532 char * end = NULL;
00533
00534 if (! strchr(" \t\n", s[2])) {
00535 fnum = s + 2;
00536 } else {
00537 fnum = strtok(NULL, " \t\n");
00538 }
00539 opt_F = (fnum ? strtol(fnum, &end, 10) : 0);
00540 if (! opt_F || *end) {
00541 rpmError(RPMERR_BADSPEC,
00542 _("line %d: Bad arg to %%patch -F: %s\n"),
00543 spec->lineNum, spec->line);
00544 return RPMERR_BADSPEC;
00545 }
00546 } else if (!strncmp(s, "-p", sizeof("-p")-1)) {
00547
00548 if (! strchr(" \t\n", s[2])) {
00549 s = s + 2;
00550 } else {
00551 s = strtok(NULL, " \t\n");
00552 if (s == NULL) {
00553 rpmError(RPMERR_BADSPEC,
00554 _("line %d: Need arg to %%patch -p: %s\n"),
00555 spec->lineNum, spec->line);
00556 return RPMERR_BADSPEC;
00557 }
00558 }
00559 if (parseNum(s, &opt_p)) {
00560 rpmError(RPMERR_BADSPEC,
00561 _("line %d: Bad arg to %%patch -p: %s\n"),
00562 spec->lineNum, spec->line);
00563 return RPMERR_BADSPEC;
00564 }
00565 } else {
00566
00567 if (patch_index == 1024) {
00568 rpmError(RPMERR_BADSPEC, _("Too many patches!\n"));
00569 return RPMERR_BADSPEC;
00570 }
00571 if (parseNum(s, &(patch_nums[patch_index]))) {
00572 rpmError(RPMERR_BADSPEC, _("line %d: Bad arg to %%patch: %s\n"),
00573 spec->lineNum, spec->line);
00574 return RPMERR_BADSPEC;
00575 }
00576 patch_index++;
00577 }
00578 }
00579
00580
00581
00582
00583 if (! opt_P) {
00584 s = doPatch(spec, 0, opt_p, opt_b, opt_R, opt_E, opt_F);
00585 if (s == NULL)
00586 return RPMERR_BADSPEC;
00587 appendLineStringBuf(spec->prep, s);
00588 }
00589
00590 for (x = 0; x < patch_index; x++) {
00591 s = doPatch(spec, patch_nums[x], opt_p, opt_b, opt_R, opt_E, opt_F);
00592 if (s == NULL)
00593 return RPMERR_BADSPEC;
00594 appendLineStringBuf(spec->prep, s);
00595 }
00596
00597 return 0;
00598 }
00599
00600
00601 int parsePrep(Spec spec)
00602 {
00603 int nextPart, res, rc;
00604 StringBuf sb;
00605 char **lines, **saveLines;
00606
00607 if (spec->prep != NULL) {
00608 rpmError(RPMERR_BADSPEC, _("line %d: second %%prep\n"), spec->lineNum);
00609 return RPMERR_BADSPEC;
00610 }
00611
00612 spec->prep = newStringBuf();
00613
00614
00615 if ((rc = readLine(spec, STRIP_NOTHING)) > 0) {
00616 return PART_NONE;
00617 }
00618 if (rc)
00619 return rc;
00620
00621 sb = newStringBuf();
00622
00623 while (! (nextPart = isPart(spec->line))) {
00624
00625
00626 appendStringBuf(sb, spec->line);
00627 if ((rc = readLine(spec, STRIP_NOTHING)) > 0) {
00628 nextPart = PART_NONE;
00629 break;
00630 }
00631 if (rc)
00632 return rc;
00633 }
00634
00635 saveLines = splitString(getStringBuf(sb), strlen(getStringBuf(sb)), '\n');
00636
00637 for (lines = saveLines; *lines; lines++) {
00638 res = 0;
00639
00640 if (! strncmp(*lines, "%setup", sizeof("%setup")-1)) {
00641 res = doSetupMacro(spec, *lines);
00642 } else if (! strncmp(*lines, "%patch", sizeof("%patch")-1)) {
00643 res = doPatchMacro(spec, *lines);
00644 } else {
00645 appendLineStringBuf(spec->prep, *lines);
00646 }
00647
00648 if (res && !spec->force) {
00649 freeSplitString(saveLines);
00650 sb = freeStringBuf(sb);
00651 return res;
00652 }
00653 }
00654
00655
00656 freeSplitString(saveLines);
00657 sb = freeStringBuf(sb);
00658
00659 return nextPart;
00660 }