rpm  4.8.1
build.c
Go to the documentation of this file.
1 
5 #include "system.h"
6 
7 #include <libgen.h>
8 
9 #include <rpm/rpmcli.h>
10 #include <rpm/rpmtag.h>
11 #include <rpm/rpmlib.h> /* rpmrc, MACHTABLE .. */
12 #include <rpm/rpmbuild.h>
13 
14 #include <rpm/rpmps.h>
15 #include <rpm/rpmte.h>
16 #include <rpm/rpmts.h>
17 #include <rpm/rpmfileutil.h>
18 #include <rpm/rpmlog.h>
19 #include <lib/misc.h>
20 
21 #include "build.h"
22 #include "debug.h"
23 
26 static int checkSpec(rpmts ts, Header h)
27 {
28  rpmps ps;
29  int rc;
30 
33  return 0;
34 
35  rc = rpmtsAddInstallElement(ts, h, NULL, 0, NULL);
36 
37  rc = rpmtsCheck(ts);
38 
39  ps = rpmtsProblems(ts);
40  if (rc == 0 && rpmpsNumProblems(ps) > 0) {
41  rpmlog(RPMLOG_ERR, _("Failed build dependencies:\n"));
42  rpmpsPrint(NULL, ps);
43  rc = 1;
44  }
45  ps = rpmpsFree(ps);
46 
47  /* XXX nuke the added package. */
48  rpmtsClean(ts);
49 
50  return rc;
51 }
52 
55 static int isSpecFile(const char * specfile)
56 {
57  char buf[256];
58  const char * s;
59  FILE * f;
60  int count;
61  int checking;
62 
63  f = fopen(specfile, "r");
64  if (f == NULL || ferror(f)) {
65  rpmlog(RPMLOG_ERR, _("Unable to open spec file %s: %s\n"),
66  specfile, strerror(errno));
67  return 0;
68  }
69  count = fread(buf, sizeof(buf[0]), sizeof(buf), f);
70  (void) fclose(f);
71 
72  if (count == 0)
73  return 0;
74 
75  checking = 1;
76  for (s = buf; count--; s++) {
77  switch (*s) {
78  case '\r':
79  case '\n':
80  checking = 1;
81  break;
82  case ':':
83  checking = 0;
84  break;
85  default:
86 #if 0
87  if (checking && !(isprint(*s) || isspace(*s))) return 0;
88  break;
89 #else
90  if (checking && !(isprint(*s) || isspace(*s)) && *(unsigned char *)s < 32) return 0;
91  break;
92 #endif
93  }
94  }
95  return 1;
96 }
97 
98 /*
99  * Try to find a spec from a tarball pointed to by arg.
100  * Return absolute path to spec name on success, otherwise NULL.
101  */
102 static char * getTarSpec(const char *arg)
103 {
104  char *specFile = NULL;
105  char *specDir;
106  char *specBase;
107  char *tmpSpecFile;
108  const char **try;
109  char tarbuf[BUFSIZ];
110  int gotspec = 0, res;
111  static const char *tryspec[] = { "Specfile", "\\*.spec", NULL };
112 
113  specDir = rpmGetPath("%{_specdir}", NULL);
114  tmpSpecFile = rpmGetPath("%{_specdir}/", "rpm-spec.XXXXXX", NULL);
115 
116  (void) close(mkstemp(tmpSpecFile));
117 
118  for (try = tryspec; *try != NULL; try++) {
119  FILE *fp;
120  char *cmd;
121 
122  cmd = rpmExpand("%{uncompress: ", arg, "} | ",
123  "%{__tar} xOvf - --wildcards ", *try,
124  " 2>&1 > ", tmpSpecFile, NULL);
125 
126  if (!(fp = popen(cmd, "r"))) {
127  rpmlog(RPMLOG_ERR, _("Failed to open tar pipe: %m\n"));
128  } else {
129  char *fok;
130  for (;;) {
131  fok = fgets(tarbuf, sizeof(tarbuf) - 1, fp);
132  /* tar sometimes prints "tar: Record size = 16" messages */
133  if (!fok || strncmp(fok, "tar: ", 5) != 0)
134  break;
135  }
136  pclose(fp);
137  gotspec = (fok != NULL) && isSpecFile(tmpSpecFile);
138  }
139 
140  if (!gotspec)
141  unlink(tmpSpecFile);
142  free(cmd);
143  }
144 
145  if (!gotspec) {
146  rpmlog(RPMLOG_ERR, _("Failed to read spec file from %s\n"), arg);
147  goto exit;
148  }
149 
150  specBase = basename(tarbuf);
151  /* remove trailing \n */
152  specBase[strlen(specBase)-1] = '\0';
153 
154  rasprintf(&specFile, "%s/%s", specDir, specBase);
155  res = rename(tmpSpecFile, specFile);
156 
157  if (res) {
158  rpmlog(RPMLOG_ERR, _("Failed to rename %s to %s: %m\n"),
159  tmpSpecFile, specFile);
160  free(specFile);
161  specFile = NULL;
162  } else {
163  /* mkstemp() can give unnecessarily strict permissions, fixup */
164  mode_t mask;
165  umask(mask = umask(0));
166  (void) chmod(specFile, 0666 & ~mask);
167  }
168 
169 exit:
170  (void) unlink(tmpSpecFile);
171  free(tmpSpecFile);
172  free(specDir);
173  return specFile;
174 }
175 
178 static int buildForTarget(rpmts ts, const char * arg, BTA_t ba)
179 {
180  const char * passPhrase = ba->passPhrase;
181  const char * cookie = ba->cookie;
182  int buildAmount = ba->buildAmount;
183  char * buildRootURL = NULL;
184  char * specFile = NULL;
185  rpmSpec spec = NULL;
186  int rc = 1; /* assume failure */
187 
188 #ifndef DYING
190 #endif
191 
192  if (ba->buildRootOverride)
193  buildRootURL = rpmGenPath(NULL, ba->buildRootOverride, NULL);
194 
195  /* Create build tree if necessary */
196  const char * buildtree = "%{_topdir}:%{_specdir}:%{_sourcedir}:%{_builddir}:%{_rpmdir}:%{_srcrpmdir}:%{_buildrootdir}";
197  const char * rootdir = rpmtsRootDir(ts);
198  if (rpmMkdirs(!rstreq(rootdir, "/") ? rootdir : NULL , buildtree)) {
199  goto exit;
200  }
201 
202  if (ba->buildMode == 't') {
203  char *srcdir = NULL, *dir;
204 
205  specFile = getTarSpec(arg);
206  if (!specFile)
207  goto exit;
208 
209  /* Make the directory of the tarball %_sourcedir for this run */
210  /* dirname() may modify contents so extra hoops needed. */
211  if (*arg != '/') {
212  dir = rpmGetCwd();
213  rstrscat(&dir, "/", arg, NULL);
214  } else {
215  dir = xstrdup(arg);
216  }
217  srcdir = dirname(dir);
218  addMacro(NULL, "_sourcedir", NULL, srcdir, RMIL_TARBALL);
219  free(dir);
220  } else {
221  specFile = xstrdup(arg);
222  }
223 
224  if (*specFile != '/') {
225  char *cwd = rpmGetCwd();
226  char *s = NULL;
227  rasprintf(&s, "%s/%s", cwd, arg);
228  free(cwd);
229  free(specFile);
230  specFile = s;
231  }
232 
233  struct stat st;
234  if (stat(specFile, &st) < 0) {
235  rpmlog(RPMLOG_ERR, _("failed to stat %s: %m\n"), specFile);
236  goto exit;
237  }
238  if (! S_ISREG(st.st_mode)) {
239  rpmlog(RPMLOG_ERR, _("File %s is not a regular file.\n"), specFile);
240  goto exit;
241  }
242 
243  /* Try to verify that the file is actually a specfile */
244  if (!isSpecFile(specFile)) {
246  _("File %s does not appear to be a specfile.\n"), specFile);
247  goto exit;
248  }
249 
250  /* Don't parse spec if only its removal is requested */
251  if (ba->buildAmount == RPMBUILD_RMSPEC) {
252  rc = unlink(specFile);
253  goto exit;
254  }
255 
256  /* Parse the spec file */
257 #define _anyarch(_f) \
258 (((_f)&(RPMBUILD_PREP|RPMBUILD_BUILD|RPMBUILD_INSTALL|RPMBUILD_PACKAGEBINARY)) == 0)
259  if (parseSpec(ts, specFile, ba->rootdir, buildRootURL, 0, passPhrase,
260  cookie, _anyarch(buildAmount), ba->force))
261  {
262  goto exit;
263  }
264 #undef _anyarch
265  if ((spec = rpmtsSetSpec(ts, NULL)) == NULL) {
266  goto exit;
267  }
268 
270  rc = doRmSource(spec);
271  if ( rc == RPMRC_OK && ba->buildAmount&RPMBUILD_RMSPEC )
272  rc = unlink(specFile);
273  goto exit;
274  }
275 
276  /* Assemble source header from parsed components */
277  initSourceHeader(spec);
278 
279  /* Check build prerequisites */
280  if (!ba->noDeps && checkSpec(ts, spec->sourceHeader)) {
281  goto exit;
282  }
283 
284  if (buildSpec(ts, spec, buildAmount, ba->noBuild)) {
285  goto exit;
286  }
287 
288  if (ba->buildMode == 't')
289  (void) unlink(specFile);
290  rc = 0;
291 
292 exit:
293  free(specFile);
294  freeSpec(spec);
295  free(buildRootURL);
296  return rc;
297 }
298 
299 int build(rpmts ts, const char * arg, BTA_t ba, const char * rcfile)
300 {
301  char *t, *te;
302  int rc = 0;
303  char * targets = ba->targets;
304 #define buildCleanMask (RPMBUILD_RMSOURCE|RPMBUILD_RMSPEC)
305  int cleanFlags = ba->buildAmount & buildCleanMask;
306  rpmVSFlags vsflags, ovsflags;
307 
308  vsflags = rpmExpandNumeric("%{_vsflags_build}");
309  if (ba->qva_flags & VERIFY_DIGEST)
310  vsflags |= _RPMVSF_NODIGESTS;
311  if (ba->qva_flags & VERIFY_SIGNATURE)
312  vsflags |= _RPMVSF_NOSIGNATURES;
313  if (ba->qva_flags & VERIFY_HDRCHK)
314  vsflags |= RPMVSF_NOHDRCHK;
315  ovsflags = rpmtsSetVSFlags(ts, vsflags);
316 
317  if (targets == NULL) {
318  rc = buildForTarget(ts, arg, ba);
319  goto exit;
320  }
321 
322  /* parse up the build operators */
323 
324  printf(_("Building target platforms: %s\n"), targets);
325 
326  ba->buildAmount &= ~buildCleanMask;
327  for (t = targets; *t != '\0'; t = te) {
328  char *target;
329  if ((te = strchr(t, ',')) == NULL)
330  te = t + strlen(t);
331  target = xmalloc(te-t+1);
332  strncpy(target, t, (te-t));
333  target[te-t] = '\0';
334  if (*te != '\0')
335  te++;
336  else /* XXX Perform clean-up after last target build. */
337  ba->buildAmount |= cleanFlags;
338 
339  printf(_("Building for target %s\n"), target);
340 
341  /* Read in configuration for target. */
342  rpmFreeMacros(NULL);
343  rpmFreeRpmrc();
344  (void) rpmReadConfigFiles(rcfile, target);
345  free(target);
346  rc = buildForTarget(ts, arg, ba);
347  if (rc)
348  break;
349  }
350 
351 exit:
352  vsflags = rpmtsSetVSFlags(ts, ovsflags);
353  /* Restore original configuration. */
354  rpmFreeMacros(NULL);
355  rpmFreeRpmrc();
356  (void) rpmReadConfigFiles(rcfile, NULL);
357 
358  return rc;
359 }
#define buildCleanMask
int headerIsEntry(Header h, rpmTag tag)
Check if tag is in header.
#define xmalloc(_size)
Definition: system.h:244
static int isSpecFile(const char *specfile)
Definition: build.c:55
int rpmtsCheck(rpmts ts)
Perform dependency resolution on the transaction set.
int build(rpmts ts, const char *arg, BTA_t ba, const char *rcfile)
Definition: build.c:299
static int buildForTarget(rpmts ts, const char *arg, BTA_t ba)
Definition: build.c:178
rpmps rpmtsProblems(rpmts ts)
Return current transaction set problems.
char * rstrscat(char **dest, const char *arg,...) RPM_GNUC_NULL_TERMINATED
Concatenate multiple strings with dynamically (re)allocated memory.
struct rpmps_s * rpmps
Transaction problems found while processing a transaction set/.
Definition: rpmps.h:42
const char * rpmtsRootDir(rpmts ts)
Get transaction rootDir, i.e.
#define _(Text)
Definition: system.h:291
void initSourceHeader(rpmSpec spec)
Create and initialize header for source package.
int rpmReadConfigFiles(const char *file, const char *target)
Read macro configuration file(s) for a target.
int parseSpec(rpmts ts, const char *specFile, const char *rootDir, const char *buildRoot, int recursing, const char *passPhrase, const char *cookie, int anyarch, int force)
Parse spec file into spec control structure.
The structure used to store values parsed from a spec file.
Definition: rpmspec.h:94
const char * rootdir
Definition: rpmcli.h:330
void rpmSetTables(int archTable, int osTable)
rpmRC doRmSource(rpmSpec spec)
Remove all sources assigned to spec file.
enum rpmVSFlags_e rpmVSFlags
Bit(s) to control digest and signature verification.
static int rstreq(const char *s1, const char *s2)
Test for string equality.
Definition: rpmstring.h:113
char * buildRootOverride
Definition: rpmcli.h:318
#define xstrdup(_str)
Definition: system.h:247
int rpmExpandNumeric(const char *arg)
Return macro expansion as a numeric value.
int rpmpsNumProblems(rpmps ps)
Return number of problems in set.
static int checkSpec(rpmts ts, Header h)
Parse spec file and build package.
Definition: build.c:26
static char * getTarSpec(const char *arg)
Definition: build.c:102
int errno
int rpmtsAddInstallElement(rpmts ts, Header h, const fnpyKey key, int upgrade, rpmRelocation *relocs)
Add package to be installed to transaction set.
int rpmMkdirs(const char *root, const char *pathstr)
Create several directories (including parents if needed) in one go.
rpmSpec rpmtsSetSpec(rpmts ts, rpmSpec spec)
Set a spec control structure in transaction set.
rpmps rpmpsFree(rpmps ps)
Destroy a problem set.
#define _anyarch(_f)
char * rpmGetPath(const char *path,...) RPM_GNUC_NULL_TERMINATED
Return (malloc&#39;ed) expanded, canonicalized, file path.
void addMacro(rpmMacroContext mc, const char *n, const char *o, const char *b, int level)
Add macro to context.
rpmSpec freeSpec(rpmSpec spec)
Destroy Spec structure.
#define _RPMVSF_NOSIGNATURES
Definition: rpmts.h:107
void rpmFreeMacros(rpmMacroContext mc)
Destroy macro context.
rpmVSFlags rpmtsSetVSFlags(rpmts ts, rpmVSFlags vsflags)
Set verify signatures flag(s).
char * rpmExpand(const char *arg,...) RPM_GNUC_NULL_TERMINATED
Return (malloc&#39;ed) concatenated macro expansion(s).
struct rpmts_s * rpmts
The main types involved in transaction manipulation.
Definition: rpmtypes.h:59
int rasprintf(char **strp, const char *fmt,...) RPM_GNUC_PRINTF(2
asprintf() clone
void rpmFreeRpmrc(void)
Destroy rpmrc arch/os compatibility tables.
#define RMIL_TARBALL
Definition: rpmmacro.h:41
#define _RPMVSF_NODIGESTS
Definition: rpmts.h:101
void rpmtsClean(rpmts ts)
Free memory needed only for dependency checks and ordering.
void rpmpsPrint(FILE *fp, rpmps ps)
Print problems to file handle.
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.
Describe build command line request.
Definition: rpmcli.h:315
rpmQueryFlags qva_flags
Definition: rpmcli.h:316
char * rpmGetCwd(void)
Like getcwd() but the result is malloced.
const char * passPhrase
Definition: rpmcli.h:320
rpmRC buildSpec(rpmts ts, rpmSpec spec, int what, int test)
Build stages state machine driver.
void rpmlog(int code, const char *fmt,...) RPM_GNUC_PRINTF(2
Generate a log message using FMT string and option arguments.
Header sourceHeader
Definition: rpmspec.h:132
struct headerToken_s * Header
RPM header and data retrieval types.
Definition: rpmtypes.h:24