static char * canonDir(rpmstrPool pool, rpmsid dirNameId) { const char * dirName = rpmstrPoolStr(pool, dirNameId); size_t cdnl = rpmstrPoolStrlen(pool, dirNameId);; char *cdnbuf = NULL; if (*dirName == '/') { cdnbuf = xstrdup(dirName); cdnbuf = rpmCleanPath(cdnbuf); /* leave my trailing slashes along you b**** */ if (cdnl > 1) cdnbuf = rstrcat(&cdnbuf, "/"); } else { /* Using realpath on the arg isn't correct if the arg is a symlink, * especially if the symlink is a dangling link. What we * do instead is use realpath() on `.' and then append arg to * the result. */ /* if the current directory doesn't exist, we might fail. oh well. likewise if it's too long. */ /* XXX we should let realpath() allocate if it can */ cdnbuf = xmalloc(PATH_MAX); cdnbuf[0] = '\0'; if (realpath(".", cdnbuf) != NULL) { char *end = cdnbuf + strlen(cdnbuf); if (end[-1] != '/') *end++ = '/'; end = stpncpy(end, dirName, PATH_MAX - (end - cdnbuf)); *end = '\0'; (void)rpmCleanPath(cdnbuf); /* XXX possible /../ from concatenation */ end = cdnbuf + strlen(cdnbuf); if (end[-1] != '/') *end++ = '/'; *end = '\0'; } else { cdnbuf = _free(cdnbuf); } } return cdnbuf; }
char * rpmGetPath(const char *path, ...) { va_list ap; char *dest = NULL, *res; const char *s; if (path == NULL) return xstrdup(""); va_start(ap, path); for (s = path; s; s = va_arg(ap, const char *)) { rstrcat(&dest, s); } va_end(ap); res = rpmExpand(dest, NULL); free(dest); return rpmCleanPath(res); }
void rpmRelocateFileList(rpmRelocation *relocations, int numRelocations, rpmfs fs, Header h) { char ** baseNames; char ** dirNames; uint32_t * dirIndexes; rpm_count_t fileCount, dirCount; int nrelocated = 0; int fileAlloced = 0; char * fn = NULL; int haveRelocatedBase = 0; size_t maxlen = 0; int i, j; struct rpmtd_s bnames, dnames, dindexes, fmodes; if (!addPrefixes(h, relocations, numRelocations)) return; if (rpmIsDebug()) { rpmlog(RPMLOG_DEBUG, "========== relocations\n"); for (i = 0; i < numRelocations; i++) { if (relocations[i].oldPath == NULL) continue; /* XXX can't happen */ if (relocations[i].newPath == NULL) rpmlog(RPMLOG_DEBUG, "%5d exclude %s\n", i, relocations[i].oldPath); else rpmlog(RPMLOG_DEBUG, "%5d relocate %s -> %s\n", i, relocations[i].oldPath, relocations[i].newPath); } } for (i = 0; i < numRelocations; i++) { if (relocations[i].newPath == NULL) continue; size_t len = strlen(relocations[i].newPath); if (len > maxlen) maxlen = len; } headerGet(h, RPMTAG_BASENAMES, &bnames, HEADERGET_MINMEM); headerGet(h, RPMTAG_DIRINDEXES, &dindexes, HEADERGET_ALLOC); headerGet(h, RPMTAG_DIRNAMES, &dnames, HEADERGET_MINMEM); headerGet(h, RPMTAG_FILEMODES, &fmodes, HEADERGET_MINMEM); /* TODO XXX ugh.. use rpmtd iterators & friends instead */ baseNames = bnames.data; dirIndexes = dindexes.data; fileCount = rpmtdCount(&bnames); dirCount = rpmtdCount(&dnames); /* XXX TODO: use rpmtdDup() instead */ dirNames = dnames.data = duparray(dnames.data, dirCount); dnames.flags |= RPMTD_PTR_ALLOCED; /* * For all relocations, we go through sorted file/relocation lists * backwards so that /usr/local relocations take precedence over /usr * ones. */ /* Relocate individual paths. */ for (i = fileCount - 1; i >= 0; i--) { rpmFileTypes ft; int fnlen; size_t len = maxlen + strlen(dirNames[dirIndexes[i]]) + strlen(baseNames[i]) + 1; if (len >= fileAlloced) { fileAlloced = len * 2; fn = xrealloc(fn, fileAlloced); } assert(fn != NULL); /* XXX can't happen */ *fn = '\0'; fnlen = stpcpy( stpcpy(fn, dirNames[dirIndexes[i]]), baseNames[i]) - fn; /* * See if this file path needs relocating. */ /* * XXX FIXME: Would a bsearch of the (already sorted) * relocation list be a good idea? */ for (j = numRelocations - 1; j >= 0; j--) { if (relocations[j].oldPath == NULL) /* XXX can't happen */ continue; len = !rstreq(relocations[j].oldPath, "/") ? strlen(relocations[j].oldPath) : 0; if (fnlen < len) continue; /* * Only subdirectories or complete file paths may be relocated. We * don't check for '\0' as our directory names all end in '/'. */ if (!(fn[len] == '/' || fnlen == len)) continue; if (!rstreqn(relocations[j].oldPath, fn, len)) continue; break; } if (j < 0) continue; rpmtdSetIndex(&fmodes, i); ft = rpmfiWhatis(rpmtdGetNumber(&fmodes)); /* On install, a relocate to NULL means skip the path. */ if (relocations[j].newPath == NULL) { if (ft == XDIR) { /* Start with the parent, looking for directory to exclude. */ for (j = dirIndexes[i]; j < dirCount; j++) { len = strlen(dirNames[j]) - 1; while (len > 0 && dirNames[j][len-1] == '/') len--; if (fnlen != len) continue; if (!rstreqn(fn, dirNames[j], fnlen)) continue; break; } } rpmfsSetAction(fs, i, FA_SKIPNSTATE); rpmlog(RPMLOG_DEBUG, "excluding %s %s\n", ftstring(ft), fn); continue; } /* Relocation on full paths only, please. */ if (fnlen != len) continue; rpmlog(RPMLOG_DEBUG, "relocating %s to %s\n", fn, relocations[j].newPath); nrelocated++; strcpy(fn, relocations[j].newPath); { char * te = strrchr(fn, '/'); if (te) { if (te > fn) te++; /* root is special */ fnlen = te - fn; } else te = fn + strlen(fn); if (!rstreq(baseNames[i], te)) { /* basename changed too? */ if (!haveRelocatedBase) { /* XXX TODO: use rpmtdDup() instead */ bnames.data = baseNames = duparray(baseNames, fileCount); bnames.flags |= RPMTD_PTR_ALLOCED; haveRelocatedBase = 1; } free(baseNames[i]); baseNames[i] = xstrdup(te); } *te = '\0'; /* terminate new directory name */ } /* Does this directory already exist in the directory list? */ for (j = 0; j < dirCount; j++) { if (fnlen != strlen(dirNames[j])) continue; if (!rstreqn(fn, dirNames[j], fnlen)) continue; break; } if (j < dirCount) { dirIndexes[i] = j; continue; } /* Creating new paths is a pita */ dirNames = dnames.data = xrealloc(dnames.data, sizeof(*dirNames) * (dirCount + 1)); dirNames[dirCount] = xstrdup(fn); dirIndexes[i] = dirCount; dirCount++; dnames.count++; } /* Finish off by relocating directories. */ for (i = dirCount - 1; i >= 0; i--) { for (j = numRelocations - 1; j >= 0; j--) { if (relocations[j].oldPath == NULL) /* XXX can't happen */ continue; size_t len = !rstreq(relocations[j].oldPath, "/") ? strlen(relocations[j].oldPath) : 0; if (len && !rstreqn(relocations[j].oldPath, dirNames[i], len)) continue; /* * Only subdirectories or complete file paths may be relocated. We * don't check for '\0' as our directory names all end in '/'. */ if (dirNames[i][len] != '/') continue; if (relocations[j].newPath) { /* Relocate the path */ char *t = NULL; rstrscat(&t, relocations[j].newPath, (dirNames[i] + len), NULL); /* Unfortunately rpmCleanPath strips the trailing slash.. */ (void) rpmCleanPath(t); rstrcat(&t, "/"); rpmlog(RPMLOG_DEBUG, "relocating directory %s to %s\n", dirNames[i], t); free(dirNames[i]); dirNames[i] = t; nrelocated++; } } } /* Save original filenames in header and replace (relocated) filenames. */ if (nrelocated) { saveOrig(h); headerMod(h, &bnames); headerMod(h, &dnames); headerMod(h, &dindexes); } rpmtdFreeData(&bnames); rpmtdFreeData(&dnames); rpmtdFreeData(&dindexes); rpmtdFreeData(&fmodes); free(fn); }
/*@-boundswrite@*/ static int buildForTarget(rpmts ts, BTA_t ba) /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ /*@modifies ts, rpmGlobalMacroContext, fileSystem, internalState @*/ { const char * passPhrase = ba->passPhrase; const char * cookie = ba->cookie; int buildAmount = ba->buildAmount; const char * specFile = NULL; const char * specURL = NULL; int specut; const char * s; char * se; const char * arg = ba->specFile; size_t nb = strlen(arg) + BUFSIZ; char * buf = alloca(nb); Spec spec = NULL; int verify = ((ba->buildAmount & RPMBUILD_TRACK) ? 0 : 1); int xx; int rc; if (ba->buildMode == 't') { static const char * sfpats[] = { "Specfile", "\\*.spec", NULL }; static const char _specfn[] = "%{mkstemp:%{_specdir}/rpm-spec.XXXXXX}"; char * tmpSpecFile = (char *) rpmGetPath(_specfn, NULL); FILE *fp; int bingo = 0; int i; for (i = 0; sfpats[i]; i++) { se = rpmExpand("%{uncompress: %{u2p:", arg, "}}", " | %{__tar} -xOvf - %{?__tar_wildcards} ", sfpats[i], " 2>&1 > '", tmpSpecFile, "'", NULL); fp = popen(se, "r"); se = _free(se); if (fp== NULL) continue; s = fgets(buf, nb - 1, fp); xx = pclose(fp); if (!s || !*s || strstr(s, ": Not found in archive")) continue; bingo = 1; break; } if (!bingo) { rpmlog(RPMLOG_ERR, _("Failed to read spec file from %s\n"), arg); xx = Unlink(tmpSpecFile); tmpSpecFile = _free(tmpSpecFile); return 1; } s = se = basename(buf); se += strlen(se); while (--se > s && strchr("\r\n", *se) != NULL) *se = '\0'; specURL = rpmGetPath("%{_specdir}/", s, NULL); specut = urlPath(specURL, &specFile); xx = Rename(tmpSpecFile, specFile); if (xx) { rpmlog(RPMLOG_ERR, _("Failed to rename %s to %s: %m\n"), tmpSpecFile, s); (void) Unlink(tmpSpecFile); } tmpSpecFile = _free(tmpSpecFile); if (xx) return 1; se = buf; *se = '\0'; se = stpcpy(se, "_sourcedir "); (void) urlPath(arg, &s); if (*s != '/') { if (getcwd(se, nb - sizeof("_sourcedir ")) != NULL) se += strlen(se); else se = stpcpy(se, "."); } else se = stpcpy(se, dirname(strcpy(se, s))); while (se > buf && se[-1] == '/') *se-- = '0'; rpmCleanPath(buf + sizeof("_sourcedir ") - 1); rpmDefineMacro(NULL, buf, RMIL_TARBALL); } else { specut = urlPath(arg, &s); se = buf; *se = '\0'; if (*s != '/') { if (getcwd(se, nb - sizeof("_sourcedir ")) != NULL) se += strlen(se); else se = stpcpy(se, "."); *se++ = '/'; se += strlen(strcpy(se,strcpy(se, s))); } else se = stpcpy(se, s); specURL = rpmGetPath(buf, NULL); specut = urlPath(specURL, &specFile); } if (specut != URL_IS_DASH) { struct stat sb; if (Stat(specURL, &sb) < 0) { rpmlog(RPMLOG_ERR, _("failed to stat %s: %m\n"), specURL); rc = 1; goto exit; } if (! S_ISREG(sb.st_mode)) { rpmlog(RPMLOG_ERR, _("File %s is not a regular file.\n"), specURL); rc = 1; goto exit; } /* Try to verify that the file is actually a specfile */ if (!isSpecFile(specURL)) { rpmlog(RPMLOG_ERR, _("File %s does not appear to be a specfile.\n"), specURL); rc = 1; goto exit; } } /* Parse the spec file */ #define _anyarch(_f) \ (((_f)&(RPMBUILD_PREP|RPMBUILD_BUILD|RPMBUILD_INSTALL|RPMBUILD_PACKAGEBINARY)) == 0) if (parseSpec(ts, specURL, ba->rootdir, 0, passPhrase, cookie, _anyarch(buildAmount), 0, verify)) { rc = 1; goto exit; } #undef _anyarch if ((spec = rpmtsSetSpec(ts, NULL)) == NULL) { rc = 1; goto exit; } /* Assemble source header from parsed components */ xx = initSourceHeader(spec, NULL); /* Check build prerequisites */ if (!ba->noDeps && checkSpec(ts, spec->sourceHeader)) { rc = 1; goto exit; } if (buildSpec(ts, spec, buildAmount, ba->noBuild)) { rc = 1; goto exit; } if (ba->buildMode == 't') (void) Unlink(specURL); rc = 0; exit: spec = freeSpec(spec); specURL = _free(specURL); return rc; }