rpm  5.4.15
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 assert(spec->dig == NULL);
345  { int xx;
346  xx = pgpDigSetAlgos(spec->dig);
347  xx = pgpImplGenerate(spec->dig);
348 assert(xx == 1);
349  xx = pgpExportPubkey(spec->dig);
350  }
351 
352  if (!spec->recursing && spec->BACount) {
353  int x;
354  /* When iterating over BANames, do the source */
355  /* packaging on the first run, and skip RMSOURCE altogether */
356  if (spec->BASpecs != NULL)
357  for (x = 0; x < spec->BACount; x++) {
358  if ((rc = buildSpec(ts, spec->BASpecs[x],
359  (what & ~RPMBUILD_RMSOURCE) |
360  (x ? 0 : (what & RPMBUILD_PACKAGESOURCE)),
361  test))) {
362  goto exit;
363  }
364  }
365  } else {
366  /* support "%track" script/section */
367  if ((what & RPMBUILD_TRACK) &&
368  (rc = doScript(spec, RPMBUILD_TRACK, NULL, NULL, test)))
369  goto exit;
370 
371  if ((what & RPMBUILD_PREP) &&
372  (rc = doScript(spec, RPMBUILD_PREP, NULL, NULL, test)))
373  goto exit;
374 
375  if ((what & RPMBUILD_BUILD) &&
376  (rc = doScript(spec, RPMBUILD_BUILD, NULL, NULL, test)))
377  goto exit;
378 
379  if ((what & RPMBUILD_INSTALL) &&
380  (rc = doScript(spec, RPMBUILD_INSTALL, NULL, NULL, test)))
381  goto exit;
382 
383  if ((what & RPMBUILD_CHECK) &&
384  (rc = doScript(spec, RPMBUILD_CHECK, NULL, NULL, test)))
385  goto exit;
386 
387  if ((what & RPMBUILD_PACKAGESOURCE) &&
388  (rc = processSourceFiles(spec)))
389  goto exit;
390 
391  if (((what & RPMBUILD_INSTALL) || (what & RPMBUILD_PACKAGEBINARY) ||
392  (what & RPMBUILD_FILECHECK)) &&
393  (rc = processBinaryFiles(spec, what & RPMBUILD_INSTALL, test)))
394  goto exit;
395 
396  if (((what & RPMBUILD_PACKAGESOURCE) && !test) &&
397  (rc = packageSources(spec)))
398  return rc;
399 
400  if (((what & RPMBUILD_PACKAGEBINARY) && !test) &&
401  (rc = packageBinaries(spec)))
402  goto exit;
403 
404  if ((what & RPMBUILD_CLEAN) &&
405  (rc = doScript(spec, RPMBUILD_CLEAN, NULL, NULL, test)))
406  goto exit;
407 
408  if ((what & RPMBUILD_RMBUILD) &&
409  (rc = doScript(spec, RPMBUILD_RMBUILD, NULL, NULL, test)))
410  goto exit;
411  }
412 
413  if (what & RPMBUILD_RMSOURCE)
414  doRmSource(spec);
415 
416  if (what & RPMBUILD_RMSPEC)
417  (void) Unlink(spec->specFile);
418 
419 #if defined(RPM_VENDOR_OPENPKG) /* auto-remove-source-directories */
420  /* In OpenPKG we use per-package %{_sourcedir} and %{_specdir}
421  definitions (macros have trailing ".../%{name}"). On removal of
422  source(s) and .spec file, this per-package directory would be kept
423  (usually <prefix>/RPM/SRC/<name>/), because RPM does not know about
424  this OpenPKG convention. So, let RPM try(!) to remove the two
425  directories (if they are empty) and just ignore removal failures
426  (if they are still not empty). */
427  if (what & RPMBUILD_RMSOURCE) {
428  const char *pn;
429  pn = rpmGetPath("%{_sourcedir}", NULL);
430  Rmdir(pn); /* ignore error, it is ok if it fails (usually with ENOTEMPTY) */
431  pn = _free(pn);
432  }
433  if (what & RPMBUILD_RMSPEC) {
434  const char *pn;
435  pn = rpmGetPath("%{_specdir}", NULL);
436  Rmdir(pn); /* ignore error, it is ok if it fails (usually with ENOTEMPTY) */
437  pn = _free(pn);
438  }
439 #endif
440 
441 exit:
442  if (rc != RPMRC_OK && rpmlogGetNrecs() > 0) {
443  rpmlog(RPMLOG_NOTICE, _("\n\nRPM build errors:\n"));
444  rpmlogPrint(NULL);
445  }
446 
447  return rc;
448 }
rpmiob build
Definition: rpmspec.h:188
rpmtime_t rpmswExit(rpmop op, ssize_t rc)
Exit timed operation.
Definition: rpmsw.c:264
rpmiob clean
Definition: rpmspec.h:194
const char bson_timestamp_t * ts
Definition: bson.h:1004
static void * fdGetFp(FD_t fd)
rpmtime_t usecs
Definition: rpmsw.h:43
rpmRC processBinaryFiles(Spec spec, int installSpecialDoc, int test)
Post-build processing for binary package(s).
Definition: files.c:3174
URL control structure.
Definition: rpmurl.h:52
const char * rootURL
Definition: rpmspec.h:120
char * rpmGetPath(const char *path,...)
Return (malloc'ed) expanded, canonicalized, file path.
Definition: macro.c:3445
const char * specFile
Definition: rpmspec.h:116
int pgpDigSetAlgos(pgpDig dig)
Definition: rpmpgp.c:1208
urltype urlType(void *_u)
Definition: url.c:424
rpmiob check
Definition: rpmspec.h:192
void addMacro(MacroContext mc, const char *n, const char *o, const char *b, int level)
Add macro to context.
Definition: macro.c:2786
struct Source * sources
Definition: rpmspec.h:162
static int pgpImplGenerate(pgpDig dig)
Definition: rpmpgp.h:1878
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:52
int pgpExportPubkey(pgpDig dig)
Definition: rpmpgp.c:1338
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:186
const char * source
Definition: rpmspec.h:48
Definition: rpmspec.h:44
char * alloca()
void delMacro(MacroContext mc, const char *n)
Delete macro from context.
Definition: macro.c:2825
rpmRC packageSources(Spec spec)
Generate source package.
Definition: pack.c:1326
int Rmdir(const char *path)
rmdir(2) clone.
Definition: rpmrpc.c:141
int recursing
Definition: rpmspec.h:149
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:177
rpmuint32_t sstates[RPMSCRIPT_MAX]
Definition: rpmspec.h:182
rpmuint32_t smetrics[RPMSCRIPT_MAX]
Definition: rpmspec.h:183
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:3491
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:113
int rpmswEnter(rpmop op, ssize_t rc)
Enter timed operation.
Definition: rpmsw.c:248
const char const bson const bson * op
Definition: mongo.h:505
char * rpmExpand(const char *arg,...)
Return (malloc'ed) concatenated macro expansion(s).
Definition: macro.c:3252
const char * buildSubdir
Definition: rpmspec.h:118
int rpmsqExecve(const char **argv)
SIGCHLD cancellation handler.
Definition: rpmsq.c:728
size_t nfoo
Definition: rpmspec.h:198
int Fclose(FD_t fd)
fclose(3) clone.
Definition: rpmio.c:2534
Cumulative statistics for an operation.
Definition: rpmsw.h:39
enum rpmfileAttrs_e rpmfileAttrs
File Attributes.
int processSourceFiles(Spec spec)
Post-build processing for source package.
Definition: files.c:2751
int BACount
Definition: rpmspec.h:148
#define RMIL_SPEC
Definition: rpmmacro.h:68
enum rpmRC_e rpmRC
RPM return codes.
pgpDig pgpDigNew(pgpVSFlags vsflags, pgpPubkeyAlgo pubkey_algo)
Create a container for parsed OpenPGP packates.
Definition: rpmpgp.c:1314
int Ferror(FD_t fd)
ferror(3) clone.
Definition: rpmio.c:2951
char * rpmiobStr(rpmiob iob)
Return I/O buffer (as string).
Definition: rpmiob.c:112
int urlSplit(const char *url, urlinfo *uret)
Parse URL string into a control structure.
Definition: url.c:476
const char const int i
Definition: bson.h:778
Spec * BASpecs
Definition: rpmspec.h:145
urltype urlPath(const char *url, const char **pathp)
Return path component of URL.
Definition: url.c:430
This is the only module users of librpmbuild should need to include.
rpmRC packageBinaries(Spec spec)
Generate binary package(s).
Definition: pack.c:1174
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:756
struct rpmiob_s * rpmiob
Definition: rpmiotypes.h:60
FD_t Fdopen(FD_t ofd, const char *fmode)
Definition: rpmio.c:2725
#define F_OK
Definition: system.h:231
void rpmlogPrint(FILE *f)
Print all rpmError() messages.
Definition: rpmlog.c:53
static const char * name
#define _(Text)
Definition: system.h:29
rpmiob install
Definition: rpmspec.h:190
tagStore_t foo
Definition: rpmspec.h:200
rpmRC buildSpec(rpmts ts, Spec spec, int what, int test)
Build stages state machine driver.
Definition: build.c:338
void * dig
Definition: rpmspec.h:202
int flags
Definition: rpmspec.h:49
int Unlink(const char *path)
unlink(2) clone.
Definition: rpmrpc.c:397