2 * \file build/parsePrep.c
3 * Parse %prep section from spec file.
8 #include <rpm/header.h>
9 #include <rpm/rpmbuild.h>
10 #include <rpm/rpmlog.h>
11 #include <rpm/rpmfileutil.h>
15 * Check that file owner and group are known.
16 * @param urlfn file url
17 * @return RPMRC_OK on success
19 static rpmRC checkOwners(const char * urlfn)
23 if (lstat(urlfn, &sb)) {
24 rpmlog(RPMLOG_ERR, _("Bad source: %s: %s\n"),
25 urlfn, strerror(errno));
28 if (!getUname(sb.st_uid) || !getGname(sb.st_gid)) {
29 rpmlog(RPMLOG_ERR, _("Bad owner/group: %s\n"), urlfn);
37 * Expand %patchN macro into %prep scriptlet.
38 * @param spec build info
39 * @param c patch index
40 * @param strip patch level (i.e. patch -p argument)
41 * @param db saved file suffix (i.e. patch --suffix argument)
42 * @param reverse include -R?
43 * @param removeEmpties include -E?
44 * @param fuzz fuzz factor, fuzz<0 means no fuzz set
45 * @param dir dir to change to (i.e. patch -d argument)
46 * @return expanded %patch macro (NULL on error)
49 static char *doPatch(rpmSpec spec, uint32_t c, int strip, const char *db,
50 int reverse, int removeEmpties, int fuzz, const char *dir)
54 char *arg_backup = NULL;
55 char *arg_fuzz = NULL;
58 char *arg_patch_flags = rpmExpand("%{?_default_patch_flags}", NULL);
62 for (sp = spec->sources; sp != NULL; sp = sp->next) {
63 if ((sp->flags & RPMBUILD_ISPATCH) && (sp->num == c)) {
69 rpmlog(RPMLOG_ERR, _("No patch number %u\n"), c);
71 rpmlog(RPMLOG_ERR, _("%%patch without corresponding \"Patch:\" tag\n"));
76 fn = rpmGetPath("%{_sourcedir}/", sp->source, NULL);
78 /* On non-build parse's, file cannot be stat'd or read. */
79 if (spec->force || checkOwners(fn)) goto exit;
82 rasprintf(&arg_backup,
83 #if HAVE_OLDPATCH_21 == 0
87 } else arg_backup = xstrdup("");
90 rasprintf(&arg_dir, " -d %s", dir);
91 } else arg_dir = xstrdup("");
94 rasprintf(&arg_fuzz, " --fuzz=%d", fuzz);
95 } else arg_fuzz = xstrdup("");
97 rasprintf(&args, "%s -p%d %s%s%s%s%s", arg_patch_flags, strip, arg_backup, arg_fuzz, arg_dir,
99 removeEmpties ? " -E" : "");
101 patchcmd = rpmExpand("%{uncompress: ", fn, "} | %{__patch} ", args, NULL);
103 free(arg_patch_flags);
110 rasprintf(&buf, "echo \"Patch #%u (%s):\"\n"
112 c, basename(fn), patchcmd);
114 rasprintf(&buf, "echo \"Patch (%s):\"\n"
116 basename(fn), patchcmd);
126 * Expand %setup macro into %prep scriptlet.
127 * @param spec build info
128 * @param c source index
129 * @param quietly should -vv be omitted from tar?
130 * @return expanded %setup macro (NULL on error)
132 static char *doUntar(rpmSpec spec, uint32_t c, int quietly)
138 rpmCompressedMagic compressed = COMPRESSED_NOT;
140 for (sp = spec->sources; sp != NULL; sp = sp->next) {
141 if ((sp->flags & RPMBUILD_ISSOURCE) && (sp->num == c)) {
147 rpmlog(RPMLOG_ERR, _("No source number %u\n"), c);
149 rpmlog(RPMLOG_ERR, _("No \"Source:\" tag in the spec file\n"));
154 fn = rpmGetPath("%{_sourcedir}/", sp->source, NULL);
157 taropts = ((rpmIsVerbose() && !quietly) ? "-xvvf" : "-xf");
159 #ifdef AUTOFETCH_NOT /* XXX don't expect this code to be enabled */
161 * XXX If nosource file doesn't exist, try to fetch from url.
162 * XXX TODO: add a "--fetch" enabler.
164 if (sp->flags & RPMTAG_NOSOURCE && autofetchnosource) {
167 if (lstat(fn, &st) != 0 && errno == ENOENT &&
168 urlIsUrl(sp->fullSource) != URL_IS_UNKNOWN) {
169 if ((rc = urlGetFile(sp->fullSource, fn)) != 0) {
171 _("Couldn't download nosource %s: %s\n"),
179 /* XXX On non-build parse's, file cannot be stat'd or read */
180 if (!spec->force && (rpmFileIsCompressed(fn, &compressed) || checkOwners(fn))) {
185 tar = rpmGetPath("%{__tar}", NULL);
186 if (compressed != COMPRESSED_NOT) {
187 char *zipper, *t = NULL;
190 switch (compressed) {
191 case COMPRESSED_NOT: /* XXX can't happen */
192 case COMPRESSED_OTHER:
195 case COMPRESSED_BZIP2:
196 t = "%{__bzip2} -dc";
199 if (rpmIsVerbose() && !quietly)
202 t = "%{__unzip} -qq";
205 case COMPRESSED_LZMA:
212 zipper = rpmGetPath(t, NULL);
214 rasprintf(&buf, "%s '%s' | %s %s - \n"
216 "if [ $STATUS -ne 0 ]; then\n"
218 "fi", zipper, fn, tar, taropts);
220 rasprintf(&buf, "%s '%s'\n"
222 "if [ $STATUS -ne 0 ]; then\n"
226 zipper = _free(zipper);
228 rasprintf(&buf, "%s %s %s", tar, taropts, fn);
237 * Parse %setup macro.
238 * @todo FIXME: Option -q broken when not immediately after %setup.
239 * @param spec build info
240 * @param line current line from spec file
241 * @return RPMRC_OK on success
243 static int doSetupMacro(rpmSpec spec, const char *line)
246 StringBuf before = newStringBuf();
247 StringBuf after = newStringBuf();
248 poptContext optCon = NULL;
250 const char ** argv = NULL;
254 rpmRC rc = RPMRC_FAIL;
256 int leaveDirs = 0, skipDefaultAction = 0;
257 int createDir = 0, quietly = 0;
258 const char * dirName = NULL;
259 struct poptOption optionsTable[] = {
260 { NULL, 'a', POPT_ARG_STRING, NULL, 'a', NULL, NULL},
261 { NULL, 'b', POPT_ARG_STRING, NULL, 'b', NULL, NULL},
262 { NULL, 'c', 0, &createDir, 0, NULL, NULL},
263 { NULL, 'D', 0, &leaveDirs, 0, NULL, NULL},
264 { NULL, 'n', POPT_ARG_STRING, &dirName, 0, NULL, NULL},
265 { NULL, 'T', 0, &skipDefaultAction, 0, NULL, NULL},
266 { NULL, 'q', 0, &quietly, 0, NULL, NULL},
267 { 0, 0, 0, 0, 0, NULL, NULL}
270 if ((xx = poptParseArgvString(line, &argc, &argv))) {
271 rpmlog(RPMLOG_ERR, _("Error parsing %%setup: %s\n"), poptStrerror(xx));
275 optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
276 while ((arg = poptGetNextOpt(optCon)) > 0) {
277 optArg = poptGetOptArg(optCon);
279 /* We only parse -a and -b here */
281 if (parseUnsignedNum(optArg, &num)) {
282 rpmlog(RPMLOG_ERR, _("line %d: Bad arg to %%setup: %s\n"),
283 spec->lineNum, (optArg ? optArg : "???"));
287 { char *chptr = doUntar(spec, num, quietly);
291 appendLineStringBuf((arg == 'a' ? after : before), chptr);
297 rpmlog(RPMLOG_ERR, _("line %d: Bad %%setup option %s: %s\n"),
299 poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
305 spec->buildSubdir = xstrdup(dirName);
307 rasprintf(&spec->buildSubdir, "%s-%s",
308 headerGetString(spec->packages->header, RPMTAG_NAME),
309 headerGetString(spec->packages->header, RPMTAG_VERSION));
311 addMacro(spec->macros, "buildsubdir", NULL, spec->buildSubdir, RMIL_SPEC);
313 /* cd to the build dir */
314 { char * buildDir = rpmGenPath(spec->rootDir, "%{_builddir}", "");
316 rasprintf(&buf, "cd '%s'", buildDir);
317 appendLineStringBuf(spec->prep, buf);
322 /* delete any old sources */
324 rasprintf(&buf, "rm -rf '%s'", spec->buildSubdir);
325 appendLineStringBuf(spec->prep, buf);
329 /* if necessary, create and cd into the proper dir */
331 rasprintf(&buf, RPM_MKDIR_P " %s\ncd '%s'",
332 spec->buildSubdir, spec->buildSubdir);
333 appendLineStringBuf(spec->prep, buf);
337 /* do the default action */
338 if (!createDir && !skipDefaultAction) {
339 char *chptr = doUntar(spec, 0, quietly);
342 appendLineStringBuf(spec->prep, chptr);
346 appendStringBuf(spec->prep, getStringBuf(before));
349 rasprintf(&buf, "cd '%s'", spec->buildSubdir);
350 appendLineStringBuf(spec->prep, buf);
354 if (createDir && !skipDefaultAction) {
355 char *chptr = doUntar(spec, 0, quietly);
358 appendLineStringBuf(spec->prep, chptr);
362 appendStringBuf(spec->prep, getStringBuf(after));
364 /* Fix the permissions of the setup build tree */
365 { char *fix = rpmExpand("%{_fixperms} .", NULL);
366 if (fix && *fix != '%') {
367 appendLineStringBuf(spec->prep, fix);
374 freeStringBuf(before);
375 freeStringBuf(after);
376 poptFreeContext(optCon);
384 * This supports too many crazy syntaxes:
385 * - %patchN is equal to %patch -P<N>
386 * - -P<N> -P<N+1>... can be used to apply several patch on a single line
387 * - Any trailing arguments are treated as patch numbers
388 * - Any combination of the above, except unless at least one -P is specified,
389 * %patch is treated as %patch -P0 so that "%patch 1" is actually
390 * equal to "%patch -P0 -P1".
392 * @param spec build info
393 * @param line current line from spec file
394 * @return RPMRC_OK on success
396 static rpmRC doPatchMacro(rpmSpec spec, const char *line)
398 char *opt_b, *opt_P, *opt_d;
400 int opt_p, opt_R, opt_E, opt_F;
402 const char **argv = NULL;
403 ARGV_t patch, patchnums = NULL;
404 rpmRC rc = RPMRC_FAIL; /* assume failure */
406 struct poptOption const patchOpts[] = {
407 { NULL, 'P', POPT_ARG_STRING, &opt_P, 'P', NULL, NULL },
408 { NULL, 'p', POPT_ARG_INT, &opt_p, 'p', NULL, NULL },
409 { NULL, 'R', POPT_ARG_NONE, &opt_R, 'R', NULL, NULL },
410 { NULL, 'E', POPT_ARG_NONE, &opt_E, 'E', NULL, NULL },
411 { NULL, 'b', POPT_ARG_STRING, &opt_b, 'b', NULL, NULL },
412 { NULL, 'z', POPT_ARG_STRING, &opt_b, 'z', NULL, NULL },
413 { NULL, 'F', POPT_ARG_INT, &opt_F, 'F', NULL, NULL },
414 { NULL, 'd', POPT_ARG_STRING, &opt_d, 'd', NULL, NULL },
415 { NULL, 0, 0, NULL, 0, NULL, NULL }
417 poptContext optCon = NULL;
419 opt_p = opt_R = opt_E = 0;
420 opt_F = rpmExpandNumeric("%{_default_patch_fuzz}"); /* get default fuzz factor for %patch */
421 opt_b = opt_d = NULL;
423 /* Convert %patchN to %patch -PN to simplify further processing */
424 if (! strchr(" \t\n", line[6])) {
425 rasprintf(&buf, "%%patch -P %s", line + 6);
427 if (strstr(line+6, " -P") == NULL)
428 rasprintf(&buf, "%%patch -P %d %s", INT_MAX, line + 6); /* INT_MAX denotes not numbered %patch */
430 buf = xstrdup(line); /* it is not numberless patch because -P is present */
432 poptParseArgvString(buf, &argc, &argv);
436 * Grab all -P<N> numbers for later processing. Stored as strings
437 * at this point so we only have to worry about conversion in one place.
439 optCon = poptGetContext(NULL, argc, argv, patchOpts, 0);
440 while ((c = poptGetNextOpt(optCon)) > 0) {
443 char *arg = poptGetOptArg(optCon);
445 argvAdd(&patchnums, arg);
456 rpmlog(RPMLOG_ERR, _("%s: %s: %s\n"), poptStrerror(c),
457 poptBadOption(optCon, POPT_BADOPTION_NOALIAS), line);
461 /* Any trailing arguments are treated as patch numbers */
462 argvAppend(&patchnums, (ARGV_const_t) poptGetArgs(optCon));
464 /* Convert to number, generate patch command and append to %prep script */
465 for (patch = patchnums; *patch; patch++) {
468 if (parseUnsignedNum(*patch, &pnum)) {
469 rpmlog(RPMLOG_ERR, _("Invalid patch number %s: %s\n"),
473 s = doPatch(spec, pnum, opt_p, opt_b, opt_R, opt_E, opt_F, opt_d);
477 appendLineStringBuf(spec->prep, s);
486 poptFreeContext(optCon);
490 int parsePrep(rpmSpec spec)
492 int nextPart, res, rc;
495 ARGV_t saveLines = NULL;
497 if (spec->prep != NULL) {
498 rpmlog(RPMLOG_ERR, _("line %d: second %%prep\n"), spec->lineNum);
502 spec->prep = newStringBuf();
504 /* There are no options to %prep */
505 if ((rc = readLine(spec, STRIP_NOTHING)) > 0) {
513 while (! (nextPart = isPart(spec->line))) {
514 /* Need to expand the macros inline. That way we */
515 /* can give good line number information on error. */
516 appendStringBuf(sb, spec->line);
517 if ((rc = readLine(spec, STRIP_NOTHING)) > 0) {
518 nextPart = PART_NONE;
525 argvSplit(&saveLines, getStringBuf(sb), "\n");
526 for (lines = saveLines; *lines; lines++) {
528 if (rstreqn(*lines, "%setup", sizeof("%setup")-1)) {
529 res = doSetupMacro(spec, *lines);
530 } else if (rstreqn(*lines, "%patch", sizeof("%patch")-1)) {
531 res = doPatchMacro(spec, *lines);
533 appendLineStringBuf(spec->prep, *lines);
535 if (res && !spec->force) {
536 /* fixup from RPMRC_FAIL do*Macro() codes for now */
537 nextPart = PART_ERROR;
545 sb = freeStringBuf(sb);