rpm 4.8.1
|
00001 00005 #include "system.h" 00006 00007 #include <libgen.h> 00008 00009 #include <rpm/rpmcli.h> 00010 #include <rpm/rpmtag.h> 00011 #include <rpm/rpmlib.h> /* rpmrc, MACHTABLE .. */ 00012 #include <rpm/rpmbuild.h> 00013 00014 #include <rpm/rpmps.h> 00015 #include <rpm/rpmte.h> 00016 #include <rpm/rpmts.h> 00017 #include <rpm/rpmfileutil.h> 00018 #include <rpm/rpmlog.h> 00019 #include <lib/misc.h> 00020 00021 #include "build.h" 00022 #include "debug.h" 00023 00026 static int checkSpec(rpmts ts, Header h) 00027 { 00028 rpmps ps; 00029 int rc; 00030 00031 if (!headerIsEntry(h, RPMTAG_REQUIRENAME) 00032 && !headerIsEntry(h, RPMTAG_CONFLICTNAME)) 00033 return 0; 00034 00035 rc = rpmtsAddInstallElement(ts, h, NULL, 0, NULL); 00036 00037 rc = rpmtsCheck(ts); 00038 00039 ps = rpmtsProblems(ts); 00040 if (rc == 0 && rpmpsNumProblems(ps) > 0) { 00041 rpmlog(RPMLOG_ERR, _("Failed build dependencies:\n")); 00042 rpmpsPrint(NULL, ps); 00043 rc = 1; 00044 } 00045 ps = rpmpsFree(ps); 00046 00047 /* XXX nuke the added package. */ 00048 rpmtsClean(ts); 00049 00050 return rc; 00051 } 00052 00055 static int isSpecFile(const char * specfile) 00056 { 00057 char buf[256]; 00058 const char * s; 00059 FILE * f; 00060 int count; 00061 int checking; 00062 00063 f = fopen(specfile, "r"); 00064 if (f == NULL || ferror(f)) { 00065 rpmlog(RPMLOG_ERR, _("Unable to open spec file %s: %s\n"), 00066 specfile, strerror(errno)); 00067 return 0; 00068 } 00069 count = fread(buf, sizeof(buf[0]), sizeof(buf), f); 00070 (void) fclose(f); 00071 00072 if (count == 0) 00073 return 0; 00074 00075 checking = 1; 00076 for (s = buf; count--; s++) { 00077 switch (*s) { 00078 case '\r': 00079 case '\n': 00080 checking = 1; 00081 break; 00082 case ':': 00083 checking = 0; 00084 break; 00085 default: 00086 #if 0 00087 if (checking && !(isprint(*s) || isspace(*s))) return 0; 00088 break; 00089 #else 00090 if (checking && !(isprint(*s) || isspace(*s)) && *(unsigned char *)s < 32) return 0; 00091 break; 00092 #endif 00093 } 00094 } 00095 return 1; 00096 } 00097 00098 /* 00099 * Try to find a spec from a tarball pointed to by arg. 00100 * Return absolute path to spec name on success, otherwise NULL. 00101 */ 00102 static char * getTarSpec(const char *arg) 00103 { 00104 char *specFile = NULL; 00105 char *specDir; 00106 char *specBase; 00107 char *tmpSpecFile; 00108 const char **try; 00109 char tarbuf[BUFSIZ]; 00110 int gotspec = 0, res; 00111 static const char *tryspec[] = { "Specfile", "\\*.spec", NULL }; 00112 00113 specDir = rpmGetPath("%{_specdir}", NULL); 00114 tmpSpecFile = rpmGetPath("%{_specdir}/", "rpm-spec.XXXXXX", NULL); 00115 00116 (void) close(mkstemp(tmpSpecFile)); 00117 00118 for (try = tryspec; *try != NULL; try++) { 00119 FILE *fp; 00120 char *cmd; 00121 00122 cmd = rpmExpand("%{uncompress: ", arg, "} | ", 00123 "%{__tar} xOvf - --wildcards ", *try, 00124 " 2>&1 > ", tmpSpecFile, NULL); 00125 00126 if (!(fp = popen(cmd, "r"))) { 00127 rpmlog(RPMLOG_ERR, _("Failed to open tar pipe: %m\n")); 00128 } else { 00129 char *fok; 00130 for (;;) { 00131 fok = fgets(tarbuf, sizeof(tarbuf) - 1, fp); 00132 /* tar sometimes prints "tar: Record size = 16" messages */ 00133 if (!fok || strncmp(fok, "tar: ", 5) != 0) 00134 break; 00135 } 00136 pclose(fp); 00137 gotspec = (fok != NULL) && isSpecFile(tmpSpecFile); 00138 } 00139 00140 if (!gotspec) 00141 unlink(tmpSpecFile); 00142 free(cmd); 00143 } 00144 00145 if (!gotspec) { 00146 rpmlog(RPMLOG_ERR, _("Failed to read spec file from %s\n"), arg); 00147 goto exit; 00148 } 00149 00150 specBase = basename(tarbuf); 00151 /* remove trailing \n */ 00152 specBase[strlen(specBase)-1] = '\0'; 00153 00154 rasprintf(&specFile, "%s/%s", specDir, specBase); 00155 res = rename(tmpSpecFile, specFile); 00156 00157 if (res) { 00158 rpmlog(RPMLOG_ERR, _("Failed to rename %s to %s: %m\n"), 00159 tmpSpecFile, specFile); 00160 free(specFile); 00161 specFile = NULL; 00162 } else { 00163 /* mkstemp() can give unnecessarily strict permissions, fixup */ 00164 mode_t mask; 00165 umask(mask = umask(0)); 00166 (void) chmod(specFile, 0666 & ~mask); 00167 } 00168 00169 exit: 00170 (void) unlink(tmpSpecFile); 00171 free(tmpSpecFile); 00172 free(specDir); 00173 return specFile; 00174 } 00175 00178 static int buildForTarget(rpmts ts, const char * arg, BTA_t ba) 00179 { 00180 const char * passPhrase = ba->passPhrase; 00181 const char * cookie = ba->cookie; 00182 int buildAmount = ba->buildAmount; 00183 char * buildRootURL = NULL; 00184 char * specFile = NULL; 00185 rpmSpec spec = NULL; 00186 int rc = 1; /* assume failure */ 00187 00188 #ifndef DYING 00189 rpmSetTables(RPM_MACHTABLE_BUILDARCH, RPM_MACHTABLE_BUILDOS); 00190 #endif 00191 00192 if (ba->buildRootOverride) 00193 buildRootURL = rpmGenPath(NULL, ba->buildRootOverride, NULL); 00194 00195 /* Create build tree if necessary */ 00196 const char * buildtree = "%{_topdir}:%{_specdir}:%{_sourcedir}:%{_builddir}:%{_rpmdir}:%{_srcrpmdir}:%{_buildrootdir}"; 00197 const char * rootdir = rpmtsRootDir(ts); 00198 if (rpmMkdirs(!rstreq(rootdir, "/") ? rootdir : NULL , buildtree)) { 00199 goto exit; 00200 } 00201 00202 if (ba->buildMode == 't') { 00203 char *srcdir = NULL, *dir; 00204 00205 specFile = getTarSpec(arg); 00206 if (!specFile) 00207 goto exit; 00208 00209 /* Make the directory of the tarball %_sourcedir for this run */ 00210 /* dirname() may modify contents so extra hoops needed. */ 00211 if (*arg != '/') { 00212 dir = rpmGetCwd(); 00213 rstrscat(&dir, "/", arg, NULL); 00214 } else { 00215 dir = xstrdup(arg); 00216 } 00217 srcdir = dirname(dir); 00218 addMacro(NULL, "_sourcedir", NULL, srcdir, RMIL_TARBALL); 00219 free(dir); 00220 } else { 00221 specFile = xstrdup(arg); 00222 } 00223 00224 if (*specFile != '/') { 00225 char *cwd = rpmGetCwd(); 00226 char *s = NULL; 00227 rasprintf(&s, "%s/%s", cwd, arg); 00228 free(cwd); 00229 free(specFile); 00230 specFile = s; 00231 } 00232 00233 struct stat st; 00234 if (stat(specFile, &st) < 0) { 00235 rpmlog(RPMLOG_ERR, _("failed to stat %s: %m\n"), specFile); 00236 goto exit; 00237 } 00238 if (! S_ISREG(st.st_mode)) { 00239 rpmlog(RPMLOG_ERR, _("File %s is not a regular file.\n"), specFile); 00240 goto exit; 00241 } 00242 00243 /* Try to verify that the file is actually a specfile */ 00244 if (!isSpecFile(specFile)) { 00245 rpmlog(RPMLOG_ERR, 00246 _("File %s does not appear to be a specfile.\n"), specFile); 00247 goto exit; 00248 } 00249 00250 /* Don't parse spec if only its removal is requested */ 00251 if (ba->buildAmount == RPMBUILD_RMSPEC) { 00252 rc = unlink(specFile); 00253 goto exit; 00254 } 00255 00256 /* Parse the spec file */ 00257 #define _anyarch(_f) \ 00258 (((_f)&(RPMBUILD_PREP|RPMBUILD_BUILD|RPMBUILD_INSTALL|RPMBUILD_PACKAGEBINARY)) == 0) 00259 if (parseSpec(ts, specFile, ba->rootdir, buildRootURL, 0, passPhrase, 00260 cookie, _anyarch(buildAmount), ba->force)) 00261 { 00262 goto exit; 00263 } 00264 #undef _anyarch 00265 if ((spec = rpmtsSetSpec(ts, NULL)) == NULL) { 00266 goto exit; 00267 } 00268 00269 if ( ba->buildAmount&RPMBUILD_RMSOURCE && !(ba->buildAmount&~(RPMBUILD_RMSOURCE|RPMBUILD_RMSPEC)) ) { 00270 rc = doRmSource(spec); 00271 if ( rc == RPMRC_OK && ba->buildAmount&RPMBUILD_RMSPEC ) 00272 rc = unlink(specFile); 00273 goto exit; 00274 } 00275 00276 /* Assemble source header from parsed components */ 00277 initSourceHeader(spec); 00278 00279 /* Check build prerequisites */ 00280 if (!ba->noDeps && checkSpec(ts, spec->sourceHeader)) { 00281 goto exit; 00282 } 00283 00284 if (buildSpec(ts, spec, buildAmount, ba->noBuild)) { 00285 goto exit; 00286 } 00287 00288 if (ba->buildMode == 't') 00289 (void) unlink(specFile); 00290 rc = 0; 00291 00292 exit: 00293 free(specFile); 00294 freeSpec(spec); 00295 free(buildRootURL); 00296 return rc; 00297 } 00298 00299 int build(rpmts ts, const char * arg, BTA_t ba, const char * rcfile) 00300 { 00301 char *t, *te; 00302 int rc = 0; 00303 char * targets = ba->targets; 00304 #define buildCleanMask (RPMBUILD_RMSOURCE|RPMBUILD_RMSPEC) 00305 int cleanFlags = ba->buildAmount & buildCleanMask; 00306 rpmVSFlags vsflags, ovsflags; 00307 00308 vsflags = rpmExpandNumeric("%{_vsflags_build}"); 00309 if (ba->qva_flags & VERIFY_DIGEST) 00310 vsflags |= _RPMVSF_NODIGESTS; 00311 if (ba->qva_flags & VERIFY_SIGNATURE) 00312 vsflags |= _RPMVSF_NOSIGNATURES; 00313 if (ba->qva_flags & VERIFY_HDRCHK) 00314 vsflags |= RPMVSF_NOHDRCHK; 00315 ovsflags = rpmtsSetVSFlags(ts, vsflags); 00316 00317 if (targets == NULL) { 00318 rc = buildForTarget(ts, arg, ba); 00319 goto exit; 00320 } 00321 00322 /* parse up the build operators */ 00323 00324 printf(_("Building target platforms: %s\n"), targets); 00325 00326 ba->buildAmount &= ~buildCleanMask; 00327 for (t = targets; *t != '\0'; t = te) { 00328 char *target; 00329 if ((te = strchr(t, ',')) == NULL) 00330 te = t + strlen(t); 00331 target = xmalloc(te-t+1); 00332 strncpy(target, t, (te-t)); 00333 target[te-t] = '\0'; 00334 if (*te != '\0') 00335 te++; 00336 else /* XXX Perform clean-up after last target build. */ 00337 ba->buildAmount |= cleanFlags; 00338 00339 printf(_("Building for target %s\n"), target); 00340 00341 /* Read in configuration for target. */ 00342 rpmFreeMacros(NULL); 00343 rpmFreeRpmrc(); 00344 (void) rpmReadConfigFiles(rcfile, target); 00345 free(target); 00346 rc = buildForTarget(ts, arg, ba); 00347 if (rc) 00348 break; 00349 } 00350 00351 exit: 00352 vsflags = rpmtsSetVSFlags(ts, ovsflags); 00353 /* Restore original configuration. */ 00354 rpmFreeMacros(NULL); 00355 rpmFreeRpmrc(); 00356 (void) rpmReadConfigFiles(rcfile, NULL); 00357 00358 return rc; 00359 }