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