rpm  5.4.10
build.c
Go to the documentation of this file.
1 
6 #include "system.h"
7 
8 #define _RPMBC_INTERNAL
9 #include <rpmio_internal.h> /* XXX fdGetFp */
10 #include <rpmcb.h>
11 #include <rpmsq.h>
12 
13 #define _RPMTAG_INTERNAL
14 #include <rpmbuild.h>
15 #include "signature.h" /* XXX rpmTempFile */
16 
17 #include "debug.h"
18 
21 #if defined(RPM_VENDOR_OPENPKG) /* splitted-source-directory */
22 const char * getSourceDir(rpmfileAttrs attr, const char *filename)
23 #else
24 const char * getSourceDir(rpmfileAttrs attr)
25 #endif
26 {
27  const char * dir = NULL;
28 #if defined(RPM_VENDOR_OPENPKG) /* splitted-source-directory */
29  const char *fn;
30 
31  /* support splitted source directories, i.e., source files which
32  are alternatively placed into the .spec directory and picked
33  up from there, too. */
34  if (attr & (RPMFILE_SOURCE|RPMFILE_PATCH|RPMFILE_ICON) && filename != NULL)
35  {
36  fn = rpmGetPath("%{_specdir}/", filename, NULL);
37  if (access(fn, F_OK) == 0)
38  dir = "%{_specdir}/";
39  fn = _free(fn);
40  }
41  if (dir != NULL) {
42  } else
43 #endif
44  if (attr & RPMFILE_SOURCE)
45  dir = "%{_sourcedir}/";
46  else if (attr & RPMFILE_PATCH)
47  dir = "%{_patchdir}/";
48  else if (attr & RPMFILE_ICON)
49  dir = "%{_icondir}/";
50 
51  return dir;
52 }
53 
54 /*@access urlinfo @*/ /* XXX compared with NULL */
55 /*@access FD_t @*/
56 
59 static void doRmSource(Spec spec)
60  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
61  /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
62 {
63  struct Source *sp;
64  int rc;
65 
66 #if 0
67  rc = Unlink(spec->specFile);
68 #endif
69 
70  for (sp = spec->sources; sp != NULL; sp = sp->next) {
71  const char *dn, *fn;
72  if (sp->flags & RPMFILE_GHOST)
73  continue;
74 #if defined(RPM_VENDOR_OPENPKG) /* splitted-source-directory */
75  if (! (dn = getSourceDir(sp->flags, sp->source)))
76 #else
77  if (! (dn = getSourceDir(sp->flags)))
78 #endif
79  continue;
80  fn = rpmGenPath(NULL, dn, sp->source);
81  rc = Unlink(fn);
82  fn = _free(fn);
83  }
84 }
85 
86 /*
87  * @todo Single use by %%doc in files.c prevents static.
88  */
89 rpmRC doScript(Spec spec, int what, const char *name, rpmiob iob, int test)
90 {
91  const char * rootURL = spec->rootURL;
92  const char * rootDir;
93  const char * scriptName = NULL;
94  const char * buildDirURL = rpmGenPath(rootURL, "%{_builddir}", "");
95  const char * buildScript;
96  const char * buildCmd = NULL;
97  const char * buildTemplate = NULL;
98  const char * buildPost = NULL;
99  const char * mTemplate = NULL;
100  const char * mCmd = NULL;
101  const char * mPost = NULL;
102  int argc = 0;
103  const char **argv = NULL;
104  FILE * fp = NULL;
105  urlinfo u = NULL;
106  rpmop op = NULL;
107  int ix = -1;
108 
109  FD_t fd;
110  FD_t xfd;
111  int status;
112  rpmRC rc;
113  size_t i;
114 
115  switch (what) {
116  case RPMBUILD_PREP:
117  name = "%prep";
118  iob = spec->prep;
119  op = memset(alloca(sizeof(*op)), 0, sizeof(*op));
120  ix = RPMSCRIPT_PREP;
121  mTemplate = "%{__spec_prep_template}";
122  mPost = "%{__spec_prep_post}";
123  mCmd = "%{__spec_prep_cmd}";
124  break;
125  case RPMBUILD_BUILD:
126  name = "%build";
127  iob = spec->build;
128  op = memset(alloca(sizeof(*op)), 0, sizeof(*op));
129  ix = RPMSCRIPT_BUILD;
130  mTemplate = "%{__spec_build_template}";
131  mPost = "%{__spec_build_post}";
132  mCmd = "%{__spec_build_cmd}";
133  break;
134  case RPMBUILD_INSTALL:
135  name = "%install";
136  iob = spec->install;
137  op = memset(alloca(sizeof(*op)), 0, sizeof(*op));
138  ix = RPMSCRIPT_INSTALL;
139  mTemplate = "%{__spec_install_template}";
140  mPost = "%{__spec_install_post}";
141  mCmd = "%{__spec_install_cmd}";
142  break;
143  case RPMBUILD_CHECK:
144  name = "%check";
145  iob = spec->check;
146  op = memset(alloca(sizeof(*op)), 0, sizeof(*op));
147  ix = RPMSCRIPT_CHECK;
148  mTemplate = "%{__spec_check_template}";
149  mPost = "%{__spec_check_post}";
150  mCmd = "%{__spec_check_cmd}";
151  break;
152  case RPMBUILD_CLEAN:
153  name = "%clean";
154  iob = spec->clean;
155  mTemplate = "%{__spec_clean_template}";
156  mPost = "%{__spec_clean_post}";
157  mCmd = "%{__spec_clean_cmd}";
158  break;
159  case RPMBUILD_RMBUILD:
160  name = "--clean";
161  mTemplate = "%{__spec_clean_template}";
162  mPost = "%{__spec_clean_post}";
163  mCmd = "%{__spec_clean_cmd}";
164  break;
165  /* support "%track" script/section */
166  case RPMBUILD_TRACK:
167  name = "%track";
168  iob = NULL;
169  if (spec->foo)
170  for (i = 0; i < spec->nfoo; i++) {
171  if (spec->foo[i].str == NULL || spec->foo[i].iob == NULL)
172  continue;
173  if (xstrcasecmp(spec->foo[i].str, "track"))
174  continue;
175  iob = spec->foo[i].iob;
176  /*@loopbreak@*/ break;
177  }
178  mTemplate = "%{__spec_track_template}";
179  mPost = "%{__spec_track_post}";
180  mCmd = "%{__spec_track_cmd}";
181  break;
182  case RPMBUILD_STRINGBUF:
183  default:
184  mTemplate = "%{___build_template}";
185  mPost = "%{___build_post}";
186  mCmd = "%{___build_cmd}";
187  break;
188  }
189 
190 assert(name != NULL);
191 
192  if ((what != RPMBUILD_RMBUILD) && iob == NULL) {
193  rc = RPMRC_OK;
194  goto exit;
195  }
196 
197  if (rpmTempFile(rootURL, &scriptName, &fd) || fd == NULL || Ferror(fd)) {
198  rpmlog(RPMLOG_ERR, _("Unable to open temp file.\n"));
199  rc = RPMRC_FAIL;
200  goto exit;
201  }
202 
203  if (fdGetFp(fd) == NULL)
204  xfd = Fdopen(fd, "w.fpio");
205  else
206  xfd = fd;
207 
208  /*@-type@*/ /* FIX: cast? */
209  if ((fp = fdGetFp(xfd)) == NULL) {
210  rc = RPMRC_FAIL;
211  goto exit;
212  }
213  /*@=type@*/
214 
215  (void) urlPath(rootURL, &rootDir);
216  if (*rootDir == '\0') rootDir = "/";
217 
218  (void) urlPath(scriptName, &buildScript);
219 
220  buildTemplate = rpmExpand(mTemplate, NULL);
221  buildPost = rpmExpand(mPost, NULL);
222 
223  (void) fputs(buildTemplate, fp);
224 
225  /* support "%track" script/section */
226  if (what != RPMBUILD_PREP && what != RPMBUILD_RMBUILD && spec->buildSubdir && what != RPMBUILD_TRACK)
227  fprintf(fp, "cd '%s'\n", spec->buildSubdir);
228 
229  if (what == RPMBUILD_RMBUILD) {
230  if (spec->buildSubdir)
231  fprintf(fp, "rm -rf '%s'\n", spec->buildSubdir);
232  } else if (iob != NULL)
233  fprintf(fp, "%s", rpmiobStr(iob));
234 
235  (void) fputs(buildPost, fp);
236 
237  (void) Fclose(xfd);
238 
239  if (test) {
240  rc = RPMRC_OK;
241  goto exit;
242  }
243 
244  if (buildDirURL && buildDirURL[0] != '/' &&
245  (urlSplit(buildDirURL, &u) != 0)) {
246  rc = RPMRC_FAIL;
247  goto exit;
248  }
249 
250  switch (urlType(u)) {
251  case URL_IS_HTTPS:
252  case URL_IS_HTTP:
253  case URL_IS_FTP:
254  addMacro(spec->macros, "_remsh", NULL, "%{__remsh}", RMIL_SPEC);
255  addMacro(spec->macros, "_remhost", NULL, u->host, RMIL_SPEC);
256  if (strcmp(rootDir, "/"))
257  addMacro(spec->macros, "_remroot", NULL, rootDir, RMIL_SPEC);
258  break;
259  case URL_IS_UNKNOWN:
260  case URL_IS_DASH:
261  case URL_IS_PATH:
262  case URL_IS_HKP:
263  case URL_IS_MONGO: /* XXX FIXME */
264  default:
265  break;
266  }
267 
268  buildCmd = rpmExpand(mCmd, " ", buildScript, NULL);
269  (void) poptParseArgvString(buildCmd, &argc, &argv);
270 
271  if (what != RPMBUILD_TRACK) /* support "%track" script/section */
272  rpmlog(RPMLOG_NOTICE, _("Executing(%s): %s\n"), name, buildCmd);
273 
274  /* Run the script with a stopwatch. */
275  if (op != NULL)
276  (void) rpmswEnter(op, 0);
277 
278  status = rpmsqExecve(argv);
279  if (ix >= 0 && ix < RPMSCRIPT_MAX)
280  spec->sstates[ix] =
282 
283  if (!WIFEXITED(status) || WEXITSTATUS(status)) {
284  rpmlog(RPMLOG_ERR, _("Bad exit status from %s (%s)\n"),
285  scriptName, name);
286  rc = RPMRC_FAIL;
287  } else
288  rc = RPMRC_OK;
289 
290  if (op != NULL) {
291  static unsigned int scale = 1000;
292  (void) rpmswExit(op, 0);
293  if (ix >= 0 && ix < RPMSCRIPT_MAX)
294  spec->smetrics[ix] += op->usecs / scale;
295  }
296 
297 exit:
298  if (scriptName) {
299 #if defined(RPM_VENDOR_OPENPKG) /* always-remove-tempfiles */
300  /* Unconditionally remove temporary files ("rpm-tmp.XXXXX") which
301  were generated for the executed scripts. In OpenPKG we run the
302  scripts in debug mode ("set -x") anyway, so we never need to
303  see the whole generated script -- not even if it breaks. Instead
304  we would just have temporary files staying around forever. */
305 #else
306  if (rc == RPMRC_OK)
307 #endif
308  (void) Unlink(scriptName);
309  scriptName = _free(scriptName);
310  }
311 
312  switch (urlType(u)) {
313  case URL_IS_HTTPS:
314  case URL_IS_HTTP:
315  case URL_IS_FTP:
316  delMacro(spec->macros, "_remsh");
317  delMacro(spec->macros, "_remhost");
318  if (strcmp(rootDir, "/"))
319  delMacro(spec->macros, "_remroot");
320  break;
321  case URL_IS_UNKNOWN:
322  case URL_IS_DASH:
323  case URL_IS_PATH:
324  case URL_IS_HKP:
325  case URL_IS_MONGO: /* XXX FIXME */
326  default:
327  break;
328  }
329 
330  argv = _free(argv);
331  buildCmd = _free(buildCmd);
332  buildTemplate = _free(buildTemplate);
333  buildPost = _free(buildPost);
334  buildDirURL = _free(buildDirURL);
335  return rc;
336 }
337 
338 rpmRC buildSpec(rpmts ts, Spec spec, int what, int test)
339 {
340  rpmRC rc = RPMRC_OK;
341 
342  /* Generate a keypair lazily. */
343  if (spec->dig == NULL)
345 
346  if (!spec->recursing && spec->BACount) {
347  int x;
348  /* When iterating over BANames, do the source */
349  /* packaging on the first run, and skip RMSOURCE altogether */
350  if (spec->BASpecs != NULL)
351  for (x = 0; x < spec->BACount; x++) {
352  if ((rc = buildSpec(ts, spec->BASpecs[x],
353  (what & ~RPMBUILD_RMSOURCE) |
354  (x ? 0 : (what & RPMBUILD_PACKAGESOURCE)),
355  test))) {
356  goto exit;
357  }
358  }
359  } else {
360  /* support "%track" script/section */
361  if ((what & RPMBUILD_TRACK) &&
362  (rc = doScript(spec, RPMBUILD_TRACK, NULL, NULL, test)))
363  goto exit;
364 
365  if ((what & RPMBUILD_PREP) &&
366  (rc = doScript(spec, RPMBUILD_PREP, NULL, NULL, test)))
367  goto exit;
368 
369  if ((what & RPMBUILD_BUILD) &&
370  (rc = doScript(spec, RPMBUILD_BUILD, NULL, NULL, test)))
371  goto exit;
372 
373  if ((what & RPMBUILD_INSTALL) &&
374  (rc = doScript(spec, RPMBUILD_INSTALL, NULL, NULL, test)))
375  goto exit;
376 
377  if ((what & RPMBUILD_CHECK) &&
378  (rc = doScript(spec, RPMBUILD_CHECK, NULL, NULL, test)))
379  goto exit;
380 
381  if ((what & RPMBUILD_PACKAGESOURCE) &&
382  (rc = processSourceFiles(spec)))
383  goto exit;
384 
385  if (((what & RPMBUILD_INSTALL) || (what & RPMBUILD_PACKAGEBINARY) ||
386  (what & RPMBUILD_FILECHECK)) &&
387  (rc = processBinaryFiles(spec, what & RPMBUILD_INSTALL, test)))
388  goto exit;
389 
390  if (((what & RPMBUILD_PACKAGESOURCE) && !test) &&
391  (rc = packageSources(spec)))
392  return rc;
393 
394  if (((what & RPMBUILD_PACKAGEBINARY) && !test) &&
395  (rc = packageBinaries(spec)))
396  goto exit;
397 
398  if ((what & RPMBUILD_CLEAN) &&
399  (rc = doScript(spec, RPMBUILD_CLEAN, NULL, NULL, test)))
400  goto exit;
401 
402  if ((what & RPMBUILD_RMBUILD) &&
403  (rc = doScript(spec, RPMBUILD_RMBUILD, NULL, NULL, test)))
404  goto exit;
405  }
406 
407  if (what & RPMBUILD_RMSOURCE)
408  doRmSource(spec);
409 
410  if (what & RPMBUILD_RMSPEC)
411  (void) Unlink(spec->specFile);
412 
413 #if defined(RPM_VENDOR_OPENPKG) /* auto-remove-source-directories */
414  /* In OpenPKG we use per-package %{_sourcedir} and %{_specdir}
415  definitions (macros have trailing ".../%{name}"). On removal of
416  source(s) and .spec file, this per-package directory would be kept
417  (usually <prefix>/RPM/SRC/<name>/), because RPM does not know about
418  this OpenPKG convention. So, let RPM try(!) to remove the two
419  directories (if they are empty) and just ignore removal failures
420  (if they are still not empty). */
421  if (what & RPMBUILD_RMSOURCE) {
422  const char *pn;
423  pn = rpmGetPath("%{_sourcedir}", NULL);
424  Rmdir(pn); /* ignore error, it is ok if it fails (usually with ENOTEMPTY) */
425  pn = _free(pn);
426  }
427  if (what & RPMBUILD_RMSPEC) {
428  const char *pn;
429  pn = rpmGetPath("%{_specdir}", NULL);
430  Rmdir(pn); /* ignore error, it is ok if it fails (usually with ENOTEMPTY) */
431  pn = _free(pn);
432  }
433 #endif
434 
435 exit:
436  if (rc != RPMRC_OK && rpmlogGetNrecs() > 0) {
437  rpmlog(RPMLOG_NOTICE, _("\n\nRPM build errors:\n"));
438  rpmlogPrint(NULL);
439  }
440 
441  return rc;
442 }