rpm/python/upgrade.c

533 lines
13 KiB
C

/** \ingroup python
* \file python/upgrade.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <glob.h> /* XXX rpmio.h */
#include <dirent.h> /* XXX rpmio.h */
#include <rpmlib.h>
#include "hash.h"
#include "upgrade.h"
#define MAXPKGS 1024
#define USEDEBUG 0
#define DEBUG(x) { \
if (USEDEBUG) \
printf x; \
}
#if 0
static void printMemStats(char *mess)
{
char buf[1024];
printf("%s\n", mess);
sprintf(buf, "cat /proc/%d/status | grep VmSize", getpid());
system(buf);
}
#endif
/*@access Header@*/ /* compared with NULL. */
/*@access rpmdbMatchIterator@*/ /* compared with NULL. */
int pkgCompare(void * first, void * second); /* XXX make gcc shut up. */
int pkgCompare(void * first, void * second) {
struct packageInfo ** a = first;
struct packageInfo ** b = second;
/* put packages w/o names at the end */
if (!(*a)->name) return 1;
if (!(*b)->name) return -1;
return xstrcasecmp((*a)->name, (*b)->name);
}
/* Adds all files in the second file list which are not in the first
file list to the hash table. */
static void compareFileList(int availFileCount, char ** availBaseNames,
char ** availDirNames, int * availDirIndexes,
int instFileCount, char ** instBaseNames,
char ** instDirNames, int * instDirIndexes,
struct hash_table *ht)
{
int installedX, availX, rc;
char * availDir, * availBase;
char * instDir, * instBase;
static int i = 0;
availX = 0;
installedX = 0;
while (installedX < instFileCount) {
instBase = instBaseNames[installedX];
instDir = instDirNames[instDirIndexes[installedX]];
if (availX == availFileCount) {
/* All the rest have moved */
DEBUG(("=> %d: %s%s\n", i++, instDir, instBase))
if (strncmp(instDir, "/etc/rc.d/", 10))
htAddToTable(ht, instDir, instBase);
installedX++;
} else {
availBase = availBaseNames[availX];
availDir = availDirNames[availDirIndexes[availX]];
rc = strcmp(availDir, instDir);
if (!rc)
rc = strcmp(availBase, instBase);
if (rc > 0) {
/* Avail > Installed -- file has moved */
DEBUG(("=> %d: %s%s\n", i++, instDir, instBase))
if (strncmp(instDir, "/etc/rc.d/", 10))
htAddToTable(ht, instDir, instBase);
installedX++;
} else if (rc < 0) {
/* Avail < Installed -- avail has some new files */
availX++;
} else {
/* Files are equal -- file not moved */
availX++;
installedX++;
}
}
}
}
static void addLostFiles(rpmdb db, struct pkgSet *psp, struct hash_table *ht)
{
char *name;
struct packageInfo **pack;
struct packageInfo key;
struct packageInfo *keyaddr = &key;
char **installedFiles;
char **installedDirs;
int_32 * installedDirIndexes;
int installedFileCount;
Header h = NULL;
rpmdbMatchIterator mi;
mi = rpmdbInitIterator(db, RPMDBI_PACKAGES, NULL, 0);
while ((h = rpmdbNextIterator(mi)) != NULL) {
(void) headerGetEntry(h, RPMTAG_NAME, NULL, (void **) &name, NULL);
if (name && !strcmp(name, "metroess")) {
/* metro was removed from 5.1, but leave it if it's already
installed */
continue;
}
key.name = name;
pack = bsearch(&keyaddr, psp->packages, psp->numPackages,
sizeof(*psp->packages), (void *)pkgCompare);
if (!pack) {
if (headerGetEntryMinMemory(h, RPMTAG_BASENAMES, NULL,
(const void **) &installedFiles, &installedFileCount)
&& headerGetEntryMinMemory(h, RPMTAG_DIRINDEXES, NULL,
(const void **) &installedDirIndexes, NULL)
&& headerGetEntryMinMemory(h, RPMTAG_DIRNAMES, NULL,
(const void **) &installedDirs, NULL))
{
compareFileList(0, NULL, NULL, NULL, installedFileCount,
installedFiles, installedDirs,
installedDirIndexes, ht);
free(installedFiles);
free(installedDirs);
}
}
}
mi = rpmdbFreeIterator(mi);
}
static int findPackagesWithObsoletes(rpmdb db, struct pkgSet *psp)
{
int count, obsoletesCount;
struct packageInfo **pip;
char **obsoletes;
count = psp->numPackages;
pip = psp->packages;
while (count--) {
if ((*pip)->selected != 0) {
pip++;
continue;
}
if (headerGetEntryMinMemory((*pip)->h, RPMTAG_OBSOLETENAME, NULL,
(const void **) &obsoletes, &obsoletesCount)) {
while (obsoletesCount--) {
if (rpmdbCountPackages(db, obsoletes[obsoletesCount]) > 0) {
(*pip)->selected = 1;
break;
}
}
free(obsoletes);
}
pip++;
}
return 0;
}
static void errorFunction(void)
{
}
static int findUpgradePackages(rpmdb db, struct pkgSet *psp,
struct hash_table *ht)
{
int skipThis;
Header h, installedHeader;
char *name;
int count;
char **installedFiles;
char ** availFiles = NULL;
char ** installedDirs;
char ** availDirs = NULL;
int_32 * installedDirIndexes;
int_32 * availDirIndexes = NULL;
int installedFileCount, availFileCount;
struct packageInfo **pip;
count = psp->numPackages;
pip = psp->packages;
while (count--) {
h = (*pip)->h;
name = NULL;
if (!headerGetEntry(h, RPMTAG_NAME, NULL, (void **) &name, NULL) ||
name == NULL)
{
/* bum header */
/*logMessage("Failed with bad header");*/
return(-1);
}
DEBUG (("Avail: %s\n", name));
{ rpmdbMatchIterator mi;
mi = rpmdbInitIterator(db, RPMTAG_NAME, name, 0);
skipThis = (mi != NULL ? 0 : 1);
(void) rpmErrorSetCallback(errorFunction);
while ((installedHeader = rpmdbNextIterator(mi)) != NULL) {
if (rpmVersionCompare(installedHeader, h) >= 0) {
/* already have a newer version installed */
DEBUG (("Already have newer version\n"))
skipThis = 1;
break;
}
}
mi = rpmdbFreeIterator(mi);
(void) rpmErrorSetCallback(NULL);
if (! skipThis) {
DEBUG (("No newer version installed\n"))
}
}
if (skipThis) {
DEBUG (("DO NOT INSTALL\n"))
} else {
DEBUG (("UPGRADE\n"))
(*pip)->selected = 1;
if (!headerGetEntryMinMemory(h, RPMTAG_BASENAMES, NULL,
(const void **) &availFiles, &availFileCount)) {
availFiles = NULL;
availFileCount = 0;
} else {
(void) headerGetEntryMinMemory(h, RPMTAG_DIRNAMES, NULL,
(const void **) &availDirs, NULL);
(void) headerGetEntryMinMemory(h, RPMTAG_DIRINDEXES, NULL,
(const void **) &availDirIndexes, NULL);
}
{ rpmdbMatchIterator mi;
mi = rpmdbInitIterator(db, RPMTAG_NAME, name, 0);
while((installedHeader = rpmdbNextIterator(mi)) != NULL) {
if (headerGetEntryMinMemory(installedHeader, RPMTAG_BASENAMES,
NULL, (const void **) &installedFiles,
&installedFileCount)
&& headerGetEntryMinMemory(installedHeader, RPMTAG_DIRNAMES,
NULL, (const void **) &installedDirs, NULL)
&& headerGetEntryMinMemory(installedHeader, RPMTAG_DIRINDEXES,
NULL, (const void **) &installedDirIndexes, NULL))
{
compareFileList(availFileCount, availFiles,
availDirs, availDirIndexes,
installedFileCount, installedFiles,
installedDirs, installedDirIndexes,
ht);
free(installedFiles);
free(installedDirs);
}
}
mi = rpmdbFreeIterator(mi);
}
if (availFiles) {
free(availFiles);
free(availDirs);
}
}
DEBUG (("\n\n"))
pip++;
}
return 0;
}
static int removeMovedFilesAlreadyHandled(struct pkgSet *psp,
struct hash_table *ht)
{
char *name;
int i, count;
Header h;
char ** availFiles, ** availDirs;
int_32 * availDirIndexes;
int availFileCount;
struct packageInfo **pip;
count = psp->numPackages;
pip = psp->packages;
while (count--) {
h = (*pip)->h;
if ((*pip)->selected != 0) {
name = NULL;
(void) headerGetEntry(h, RPMTAG_NAME, NULL, (void **) &name, NULL);
if (headerGetEntryMinMemory(h, RPMTAG_BASENAMES, NULL,
(const void **) &availFiles, &availFileCount)
&& headerGetEntryMinMemory(h, RPMTAG_DIRNAMES, NULL,
(const void **) &availDirs, NULL)
&& headerGetEntryMinMemory(h, RPMTAG_DIRINDEXES, NULL,
(const void **) &availDirIndexes, NULL))
{
for (i = 0; i < availFileCount; i++) {
if (htInTable(ht, availDirs[availDirIndexes[i]],
availFiles[i])) {
htRemoveFromTable(ht, availDirs[availDirIndexes[i]],
availFiles[i]);
DEBUG (("File already in %s: %s%s\n", name,
availDirs[availDirIndexes[i]], availFiles[i]))
break;
}
}
free(availFiles);
free(availDirs);
}
}
pip++;
}
return 0;
}
static int findPackagesWithRelocatedFiles(struct pkgSet *psp,
struct hash_table *ht)
{
char *name;
int i, count;
Header h;
char **availFiles, **availDirs;
int_32 * availDirIndexes;
int availFileCount;
struct packageInfo **pip;
int_16 * availFileModes;
count = psp->numPackages;
pip = psp->packages;
while (count--) {
h = (*pip)->h;
if (! (*pip)->selected) {
name = NULL;
(void) headerGetEntry(h, RPMTAG_NAME, NULL, (void **) &name, NULL);
if (headerGetEntry(h, RPMTAG_BASENAMES, NULL,
(void **) &availFiles, &availFileCount)
&& headerGetEntryMinMemory(h, RPMTAG_DIRNAMES, NULL,
(const void **) &availDirs, NULL)
&& headerGetEntryMinMemory(h, RPMTAG_DIRINDEXES, NULL,
(const void **) &availDirIndexes, NULL)
&& headerGetEntryMinMemory(h, RPMTAG_FILEMODES, NULL,
(const void **) &availFileModes, NULL))
{
for (i = 0; i < availFileCount; i++) {
if (S_ISDIR(availFileModes[i])) continue;
if (htInTable(ht, availDirs[availDirIndexes[i]],
availFiles[i])) {
htRemoveFromTable(ht, availDirs[availDirIndexes[i]],
availFiles[i]);
DEBUG (("Found file in %s: %s%s\n", name,
availDirs[availDirIndexes[i]], availFiles[i]))
(*pip)->selected = 1;
}
}
free(availFiles);
free(availDirs);
}
}
pip++;
}
return 0;
}
/*
static void printCount(struct pkgSet *psp)
{
int i, upgradeCount;
struct packageInfo *pip;
upgradeCount = 0;
pip = psp->packages;
i = psp->numPackages;
while (i--) {
if (pip->selected) {
upgradeCount++;
}
pip++;
}
logMessage("marked %d packages for upgrade", upgradeCount);
}
*/
static int unmarkPackagesAlreadyInstalled(rpmdb db, struct pkgSet *psp)
{
Header h, installedHeader;
char *name;
struct packageInfo **pip;
int count;
count = psp->numPackages;
pip = psp->packages;
while (count--) {
if ((*pip)->selected != 0) {
h = (*pip)->h;
/* If this package is already installed, don't bother */
name = NULL;
if (!headerGetEntry(h, RPMTAG_NAME, NULL, (void **) &name, NULL) ||
name == NULL)
{
/* bum header */
/*logMessage("Failed with bad header");*/
return(-1);
}
{ rpmdbMatchIterator mi;
mi = rpmdbInitIterator(db, RPMTAG_NAME, name, 0);
(void) rpmErrorSetCallback(errorFunction);
while((installedHeader = rpmdbNextIterator(mi)) != NULL) {
if (rpmVersionCompare(installedHeader, h) >= 0) {
/* already have a newer version installed */
DEBUG (("Already have newer version\n"))
(*pip)->selected = 0;
break;
}
}
mi = rpmdbFreeIterator(mi);
(void) rpmErrorSetCallback(NULL);
}
}
pip++;
}
return 0;
}
static void emptyErrorCallback(void) {
}
int ugFindUpgradePackages(struct pkgSet *psp, char *installRoot)
{
rpmdb db;
struct hash_table *hashTable;
rpmErrorCallBackType old;
/*logDebugMessage(("ugFindUpgradePackages() ..."));*/
/* rpmReadConfigFiles(NULL, NULL); */
rpmSetVerbosity(RPMMESS_FATALERROR);
old = rpmErrorSetCallback(emptyErrorCallback);
if (rpmdbOpen(installRoot, &db, O_RDONLY, 0644)) {
/*logMessage("failed opening %s/var/lib/rpm/packages.rpm",
installRoot);*/
return(-1);
}
(void) rpmErrorSetCallback(old);
rpmSetVerbosity(RPMMESS_NORMAL);
hashTable = htNewTable(1103);
if (hashTable == NULL) return (-1);
/* For all packages that are installed, if there is no package */
/* available by that name, add the package's files to the hash table */
addLostFiles(db, psp, hashTable);
/*logDebugMessage(("added lost files"));
printCount(psp);*/
/* Find packges that are new, and mark them in installThisPackage, */
/* updating availPkgs with the count. Also add files to the hash */
/* table that do not exist in the new package - they may have moved */
if (findUpgradePackages(db, psp, hashTable)) {
(void) rpmdbClose(db);
return(-1);
}
/*logDebugMessage(("found basic packages to upgrade"));
printCount(psp);
hash_stats(hashTable);*/
/* Remove any files that were added to the hash table that are in */
/* some other package marked for upgrade. */
(void) removeMovedFilesAlreadyHandled(psp, hashTable);
/*logDebugMessage(("removed extra files which have moved"));
printCount(psp);*/
(void) findPackagesWithRelocatedFiles(psp, hashTable);
/*logDebugMessage(("found packages with relocated files"));
printCount(psp);*/
(void) findPackagesWithObsoletes(db, psp);
/*logDebugMessage(("found packages that obsolete installed packages"));
printCount(psp);*/
(void) unmarkPackagesAlreadyInstalled(db, psp);
/*logDebugMessage(("unmarked packages already installed"));
printCount(psp);*/
htFreeHashTable(hashTable);
/*printMemStats("Done");*/
(void) rpmdbClose(db);
return 0;
}