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 = "%{__spec_stringbuf_template}";
185  mPost = "%{__spec_stringbuf_post}";
186  mCmd = "%{__spec_stringbuf_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 }
rpmiob build
Definition: rpmspec.h:183
rpmtime_t rpmswExit(rpmop op, ssize_t rc)
Exit timed operation.
Definition: rpmsw.c:264
rpmiob clean
Definition: rpmspec.h:189
static void * fdGetFp(FD_t fd)
rpmtime_t usecs
Definition: rpmsw.h:37
rpmRC processBinaryFiles(Spec spec, int installSpecialDoc, int test)
Post-build processing for binary package(s).
Definition: files.c:3144
URL control structure.
Definition: rpmurl.h:52
const char * rootURL
Definition: rpmspec.h:115
char * rpmGetPath(const char *path,...)
Return (malloc&#39;ed) expanded, canonicalized, file path.
Definition: macro.c:3310
const char * specFile
Definition: rpmspec.h:111
urltype urlType(void *_u)
Definition: url.c:423
rpmiob check
Definition: rpmspec.h:187
void addMacro(MacroContext mc, const char *n, const char *o, const char *b, int level)
Add macro to context.
Definition: macro.c:2684
struct Source * sources
Definition: rpmspec.h:157
static void rpmlog(int code, const char *fmt,...)
Definition: rpmlog.h:299
const char * host
Definition: rpmurl.h:63
struct Source * next
Definition: rpmspec.h:47
const char * getSourceDir(rpmfileAttrs attr)
Return the macro directory location from source file flags.
Definition: build.c:24
static void doRmSource(Spec spec)
Definition: build.c:59
rpmiob prep
Definition: rpmspec.h:181
const char * source
Definition: rpmspec.h:43
Definition: rpmspec.h:39
char * alloca()
void delMacro(MacroContext mc, const char *n)
Delete macro from context.
Definition: macro.c:2723
rpmRC packageSources(Spec spec)
Generate source package.
Definition: pack.c:1301
int Rmdir(const char *path)
rmdir(2) clone.
Definition: rpmrpc.c:141
int recursing
Definition: rpmspec.h:144
int rpmlogGetNrecs(void)
Return number of messages.
Definition: rpmlog.c:23
int rpmTempFile(const char *prefix, const char **fnptr, void *fdptr)
Return file handle for a temporaray file.
Definition: signature.c:30
MacroContext macros
Definition: rpmspec.h:172
rpmuint32_t sstates[RPMSCRIPT_MAX]
Definition: rpmspec.h:177
rpmuint32_t smetrics[RPMSCRIPT_MAX]
Definition: rpmspec.h:178
The FD_t File Handle data structure.
const char * rpmGenPath(const char *urlroot, const char *urlmdir, const char *urlfile)
Merge 3 args into path, any or all of which may be a url.
Definition: macro.c:3356
Generate and verify rpm package signatures.
int xstrcasecmp(const char *s1, const char *s2)
Locale insensitive strcasecmp(3).
Definition: strcasecmp.c:9
The structure used to store values parsed from a spec file.
Definition: rpmspec.h:108
int rpmswEnter(rpmop op, ssize_t rc)
Enter timed operation.
Definition: rpmsw.c:248
char * rpmExpand(const char *arg,...)
Return (malloc&#39;ed) concatenated macro expansion(s).
Definition: macro.c:3117
const char * buildSubdir
Definition: rpmspec.h:113
int rpmsqExecve(const char **argv)
SIGCHLD cancellation handler.
Definition: rpmsq.c:728
size_t nfoo
Definition: rpmspec.h:191
int Fclose(FD_t fd)
fclose(3) clone.
Definition: rpmio.c:2534
Cumulative statistics for an operation.
Definition: rpmsw.h:33
enum rpmfileAttrs_e rpmfileAttrs
File Attributes.
int processSourceFiles(Spec spec)
Post-build processing for source package.
Definition: files.c:2737
int BACount
Definition: rpmspec.h:143
#define RMIL_SPEC
Definition: rpmmacro.h:56
enum rpmRC_e rpmRC
RPM return codes.
pgpDig pgpDigNew(pgpVSFlags vsflags, pgpPubkeyAlgo pubkey_algo)
Create a container for parsed OpenPGP packates.
Definition: rpmpgp.c:1206
int Ferror(FD_t fd)
ferror(3) clone.
Definition: rpmio.c:2944
char * rpmiobStr(rpmiob iob)
Return I/O buffer (as string).
Definition: rpmiob.c:113
int urlSplit(const char *url, urlinfo *uret)
Parse URL string into a control structure.
Definition: url.c:476
Spec * BASpecs
Definition: rpmspec.h:140
urltype urlPath(const char *url, const char **pathp)
Return path component of URL.
Definition: url.c:429
This is the only module users of librpmbuild should need to include.
rpmRC packageBinaries(Spec spec)
Generate binary package(s).
Definition: pack.c:1149
rpmRC doScript(Spec spec, int what, const char *name, rpmiob iob, int test)
Run a build script, assembled from spec file scriptlet section.
Definition: build.c:89
struct rpmts_s * rpmts
The RPM Transaction Set.
Definition: rpmtypes.h:14
static void * _free(const void *p)
Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
Definition: rpmiotypes.h:647
struct rpmiob_s * rpmiob
Definition: rpmiotypes.h:57
FD_t Fdopen(FD_t ofd, const char *fmode)
Definition: rpmio.c:2718
#define F_OK
Definition: system.h:216
void rpmlogPrint(FILE *f)
Print all rpmError() messages.
Definition: rpmlog.c:55
static const char * name
#define _(Text)
Definition: system.h:30
rpmiob install
Definition: rpmspec.h:185
tagStore_t foo
Definition: rpmspec.h:193
rpmRC buildSpec(rpmts ts, Spec spec, int what, int test)
Build stages state machine driver.
Definition: build.c:338
void * dig
Definition: rpmspec.h:195
int flags
Definition: rpmspec.h:44
int Unlink(const char *path)
unlink(2) clone.
Definition: rpmrpc.c:397