rpm/install.c

510 lines
13 KiB
C

#include "system.h"
#include "build/rpmbuild.h"
#include "install.h"
#include "url.h"
#include "ftp.h"
static void printHash(const unsigned long amount, const unsigned long total);
static void * showProgress(const Header h, const rpmCallbackType what,
const unsigned long amount,
const unsigned long total,
const void * pkgKey, void * data);
static int hashesPrinted = 0;
static void printHash(const unsigned long amount, const unsigned long total) {
int hashesNeeded;
if (hashesPrinted != 50) {
hashesNeeded = 50 * (total ? (((float) amount) / total) : 1);
while (hashesNeeded > hashesPrinted) {
printf("#");
fflush(stdout);
hashesPrinted++;
}
fflush(stdout);
hashesPrinted = hashesNeeded;
if (hashesPrinted == 50)
fprintf(stdout, "\n");
}
}
static void * showProgress(const Header h, const rpmCallbackType what,
const unsigned long amount,
const unsigned long total,
const void * pkgKey, void * data) {
char * s;
int flags = (int) data;
void * rc = NULL;
const char * filename = pkgKey;
static FD_t fd;
switch (what) {
case RPMCALLBACK_INST_OPEN_FILE:
fd = fdOpen(filename, O_RDONLY, 0);
return fd;
case RPMCALLBACK_INST_CLOSE_FILE:
fdClose(fd);
break;
case RPMCALLBACK_INST_START:
hashesPrinted = 0;
if (flags & INSTALL_LABEL) {
if (flags & INSTALL_HASH) {
s = headerSprintf(h, "%{NAME}",
rpmTagTable, rpmHeaderFormats, NULL);
printf("%-28s", s);
fflush(stdout);
} else {
s = headerSprintf(h, "%{NAME}-%{VERSION}-%{RELEASE}",
rpmTagTable, rpmHeaderFormats, NULL);
printf("%s\n", s);
}
free(s);
}
break;
case RPMCALLBACK_INST_PROGRESS:
if (flags & INSTALL_PERCENT) {
fprintf(stdout, "%%%% %f\n", (total
? ((float) ((((float) amount) / total) * 100))
: 100.0));
} else if (flags & INSTALL_HASH) {
printHash(amount, total);
}
break;
case RPMCALLBACK_TRANS_PROGRESS:
case RPMCALLBACK_TRANS_START:
case RPMCALLBACK_TRANS_STOP:
case RPMCALLBACK_UNINST_PROGRESS:
case RPMCALLBACK_UNINST_START:
case RPMCALLBACK_UNINST_STOP:
/* ignore */
break;
}
return rc;
}
int doInstall(const char * rootdir, const char ** argv, int transFlags,
int interfaceFlags, int probFilter,
rpmRelocation * relocations) {
rpmdb db = NULL;
FD_t fd;
int i;
int mode, rc, major;
const char ** packages, ** tmpPackages;
const char ** filename;
int numPackages;
int numTmpPackages = 0, numBinaryPackages = 0, numSourcePackages = 0;
int numFailed = 0;
Header h;
int isSource;
rpmTransactionSet rpmdep = NULL;
struct rpmDependencyConflict * conflicts;
int numConflicts;
int stopInstall = 0;
size_t nb;
int notifyFlags = interfaceFlags | (rpmIsVerbose() ? INSTALL_LABEL : 0 );
int dbIsOpen = 0;
const char ** sourcePackages;
rpmRelocation * defaultReloc;
if (transFlags & RPMTRANS_FLAG_TEST)
mode = O_RDONLY;
else
mode = O_RDWR | O_CREAT;
for (defaultReloc = relocations; defaultReloc && defaultReloc->oldPath;
defaultReloc++);
if (defaultReloc && !defaultReloc->newPath) defaultReloc = NULL;
rpmMessage(RPMMESS_DEBUG, _("counting packages to install\n"));
for (filename = argv, numPackages = 0; *filename; filename++, numPackages++)
;
rpmMessage(RPMMESS_DEBUG, _("found %d packages\n"), numPackages);
nb = (numPackages + 1) * sizeof(char *);
packages = alloca(nb);
memset(packages, 0, nb);
tmpPackages = alloca(nb);
memset(tmpPackages, 0, nb);
nb = (numPackages + 1) * sizeof(Header);
rpmMessage(RPMMESS_DEBUG, _("looking for packages to download\n"));
for (filename = argv, i = 0; *filename; filename++) {
switch (urlIsURL(*filename)) {
case URL_IS_FTP:
case URL_IS_HTTP:
case URL_IS_PATH:
{ int myrc;
const char *tfn;
if (rpmIsVerbose())
fprintf(stdout, _("Retrieving %s\n"), *filename);
{ char tfnbuf[64];
strcpy(tfnbuf, "rpm-xfer.XXXXXX");
/* XXX watchout for rootdir = NULL */
tfn = rpmGetPath( (rootdir ? rootdir : ""),
"%{_tmppath}/", mktemp(tfnbuf), NULL);
}
rpmMessage(RPMMESS_DEBUG, _(" ... as %s\n"), tfn);
myrc = urlGetFile(*filename, tfn);
if (myrc < 0) {
rpmMessage(RPMMESS_ERROR,
_("skipping %s - transfer failed - %s\n"),
*filename, ftpStrerror(myrc));
numFailed++;
packages[i] = NULL;
xfree(tfn);
} else {
tmpPackages[numTmpPackages++] = packages[i++] = tfn;
}
} break;
default:
packages[i++] = *filename;
break;
}
}
sourcePackages = alloca(sizeof(*sourcePackages) * i);
rpmMessage(RPMMESS_DEBUG, _("retrieved %d packages\n"), numTmpPackages);
/* Build up the transaction set. As a special case, v1 source packages
are installed right here, only because they don't have headers and
would create all sorts of confusion later. */
for (filename = packages; *filename; filename++) {
fd = fdOpen(*filename, O_RDONLY, 0);
if (fdFileno(fd) < 0) {
rpmMessage(RPMMESS_ERROR, _("cannot open file %s\n"), *filename);
numFailed++;
packages[i] = NULL;
continue;
}
rc = rpmReadPackageHeader(fd, &h, &isSource, &major, NULL);
switch (rc) {
case 1:
fdClose(fd);
rpmMessage(RPMMESS_ERROR,
_("%s does not appear to be a RPM package\n"),
*filename);
break;
default:
rpmMessage(RPMMESS_ERROR, _("%s cannot be installed\n"), *filename);
numFailed++;
packages[i] = NULL;
break;
case 0:
if (isSource) {
sourcePackages[numSourcePackages++] = *filename;
fdClose(fd);
} else {
if (!dbIsOpen) {
if (rpmdbOpen(rootdir, &db, mode, 0644)) {
const char *dn;
dn = rpmGetPath( (rootdir ? rootdir : ""),
"%{_dbpath}", NULL);
rpmMessage(RPMMESS_ERROR,
_("cannot open %s/packages.rpm\n"), dn);
xfree(dn);
exit(EXIT_FAILURE);
}
rpmdep = rpmtransCreateSet(db, rootdir);
dbIsOpen = 1;
}
if (defaultReloc) {
char ** paths;
char * name;
int c;
if (headerGetEntry(h, RPMTAG_PREFIXES, NULL,
(void **) &paths, &c) && (c == 1)) {
defaultReloc->oldPath = paths[0];
free(paths);
} else {
headerGetEntry(h, RPMTAG_NAME, NULL, (void **) &name,
NULL);
rpmMessage(RPMMESS_ERROR,
_("package %s is not relocateable\n"), name);
return numPackages;
}
}
rc = rpmtransAddPackage(rpmdep, h, NULL, *filename,
(interfaceFlags & INSTALL_UPGRADE) != 0,
relocations);
if (rc) {
if (rc == 1)
rpmMessage(RPMMESS_ERROR,
_("error reading from file %s\n"), *filename);
else if (rc == 2)
rpmMessage(RPMMESS_ERROR,
_("file %s requires a newer version of RPM\n"),
*filename);
return numPackages;
}
if (defaultReloc)
defaultReloc->oldPath = NULL;
fdClose(fd);
numBinaryPackages++;
}
break;
}
}
rpmMessage(RPMMESS_DEBUG, _("found %d source and %d binary packages\n"),
numSourcePackages, numBinaryPackages);
if (numBinaryPackages && !(interfaceFlags & INSTALL_NODEPS)) {
if (rpmdepCheck(rpmdep, &conflicts, &numConflicts)) {
numFailed = numPackages;
stopInstall = 1;
}
if (!stopInstall && conflicts) {
rpmMessage(RPMMESS_ERROR, _("failed dependencies:\n"));
printDepProblems(stderr, conflicts, numConflicts);
rpmdepFreeConflicts(conflicts, numConflicts);
numFailed = numPackages;
stopInstall = 1;
}
}
if (numBinaryPackages && !(interfaceFlags & INSTALL_NOORDER)) {
if (rpmdepOrder(rpmdep)) {
numFailed = numPackages;
stopInstall = 1;
}
}
if (numBinaryPackages && !stopInstall) {
rpmProblemSet probs = NULL;
;
rpmMessage(RPMMESS_DEBUG, _("installing binary packages\n"));
rc = rpmRunTransactions(rpmdep, showProgress, (void *) notifyFlags,
NULL, &probs, transFlags, probFilter);
if (rc < 0) {
numFailed += numBinaryPackages;
} else if (rc) {
numFailed += rc;
for (i = 0; i < probs->numProblems; i++) {
if (!probs->probs[i].ignoreProblem) {
char *msg = rpmProblemString(probs->probs[i]);
rpmMessage(RPMMESS_ERROR, "%s\n", msg);
free(msg);
}
}
}
if (probs) rpmProblemSetFree(probs);
}
if (numBinaryPackages) rpmtransFree(rpmdep);
if (numSourcePackages && !stopInstall) {
for (i = 0; i < numSourcePackages; i++) {
fd = fdOpen(sourcePackages[i], O_RDONLY, 0);
if (fdFileno(fd) < 0) {
rpmMessage(RPMMESS_ERROR, _("cannot open file %s\n"),
sourcePackages[i]);
continue;
}
if (!(transFlags & RPMTRANS_FLAG_TEST))
numFailed += rpmInstallSourcePackage(rootdir, fd, NULL,
showProgress, (void *) notifyFlags, NULL);
fdClose(fd);
}
}
for (i = 0; i < numTmpPackages; i++) {
unlink(tmpPackages[i]);
xfree(tmpPackages[i]);
}
/* FIXME how do we close our various fd's? */
if (dbIsOpen) rpmdbClose(db);
return numFailed;
}
int doUninstall(const char * rootdir, const char ** argv, int transFlags,
int interfaceFlags) {
rpmdb db;
dbiIndexSet matches;
int i, j;
int mode;
int rc;
int count;
const char ** arg;
int numFailed = 0;
rpmTransactionSet rpmdep;
struct rpmDependencyConflict * conflicts;
int numConflicts;
int stopUninstall = 0;
int numPackages = 0;
rpmProblemSet probs;
if (transFlags & RPMTRANS_FLAG_TEST)
mode = O_RDONLY;
else
mode = O_RDWR | O_EXCL;
if (rpmdbOpen(rootdir, &db, mode, 0644)) {
const char *dn;
dn = rpmGetPath( (rootdir ? rootdir : ""), "%{_dbpath}", NULL);
rpmMessage(RPMMESS_ERROR, _("cannot open %s/packages.rpm\n"), dn);
xfree(dn);
exit(EXIT_FAILURE);
}
j = 0;
rpmdep = rpmtransCreateSet(db, rootdir);
for (arg = argv; *arg; arg++) {
rc = rpmdbFindByLabel(db, *arg, &matches);
switch (rc) {
case 1:
rpmMessage(RPMMESS_ERROR, _("package %s is not installed\n"), *arg);
numFailed++;
break;
case 2:
rpmMessage(RPMMESS_ERROR, _("searching for package %s\n"), *arg);
numFailed++;
break;
default:
count = 0;
for (i = 0; i < dbiIndexSetCount(matches); i++)
if (dbiIndexRecordOffset(matches, i)) count++;
if (count > 1 && !(interfaceFlags & UNINSTALL_ALLMATCHES)) {
rpmMessage(RPMMESS_ERROR, _("\"%s\" specifies multiple packages\n"),
*arg);
numFailed++;
}
else {
for (i = 0; i < dbiIndexSetCount(matches); i++) {
unsigned int recOffset = dbiIndexRecordOffset(matches, i);
if (recOffset) {
rpmtransRemovePackage(rpmdep, recOffset);
numPackages++;
}
}
}
dbiFreeIndexRecord(matches);
break;
}
}
if (!(interfaceFlags & UNINSTALL_NODEPS)) {
if (rpmdepCheck(rpmdep, &conflicts, &numConflicts)) {
numFailed = numPackages;
stopUninstall = 1;
}
if (!stopUninstall && conflicts) {
rpmMessage(RPMMESS_ERROR, _("removing these packages would break "
"dependencies:\n"));
printDepProblems(stderr, conflicts, numConflicts);
rpmdepFreeConflicts(conflicts, numConflicts);
numFailed += numPackages;
stopUninstall = 1;
}
}
if (!stopUninstall) {
numFailed += rpmRunTransactions(rpmdep, NULL, NULL, NULL, &probs,
transFlags, 0);
}
rpmtransFree(rpmdep);
rpmdbClose(db);
return numFailed;
}
int doSourceInstall(const char * rootdir, const char * arg, const char ** specFile,
char ** cookie) {
FD_t fd;
int rc;
fd = fdOpen(arg, O_RDONLY, 0);
if (fdFileno(fd) < 0) {
rpmMessage(RPMMESS_ERROR, _("cannot open %s\n"), arg);
return 1;
}
if (rpmIsVerbose())
fprintf(stdout, _("Installing %s\n"), arg);
rc = rpmInstallSourcePackage(rootdir, fd, specFile, NULL, NULL,
cookie);
if (rc == 1) {
rpmMessage(RPMMESS_ERROR, _("%s cannot be installed\n"), arg);
if (specFile) FREE(*specFile);
if (cookie) FREE(*cookie);
}
fdClose(fd);
return rc;
}
void printDepFlags(FILE * f, const char * version, int flags) {
if (flags)
fprintf(f, " ");
if (flags & RPMSENSE_LESS)
fprintf(f, "<");
if (flags & RPMSENSE_GREATER)
fprintf(f, ">");
if (flags & RPMSENSE_EQUAL)
fprintf(f, "=");
if (flags & RPMSENSE_SERIAL)
fprintf(f, "S");
if (flags)
fprintf(f, " %s", version);
}
void printDepProblems(FILE * f, struct rpmDependencyConflict * conflicts,
int numConflicts) {
int i;
for (i = 0; i < numConflicts; i++) {
fprintf(f, "\t%s", conflicts[i].needsName);
if (conflicts[i].needsFlags) {
printDepFlags(stderr, conflicts[i].needsVersion,
conflicts[i].needsFlags);
}
if (conflicts[i].sense == RPMDEP_SENSE_REQUIRES)
fprintf(f, _(" is needed by %s-%s-%s\n"), conflicts[i].byName,
conflicts[i].byVersion, conflicts[i].byRelease);
else
fprintf(f, _(" conflicts with %s-%s-%s\n"), conflicts[i].byName,
conflicts[i].byVersion, conflicts[i].byRelease);
}
}