/* * autoupgrade.c : handling of autoupgrades * * See Copyright for the status of this software. * * Daniel.Veillard@w3.org */ #include "config.h" #include #include #include #include #ifdef HAVE_SYS_UTSNAME #include #endif #ifdef HAVE_FCNTL_H #include #endif #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include #include #ifdef HAVE_SIGNAL_H #include #endif #ifdef HAVE_REGEX_H #include #else #ifdef HAVE_RXPOSIX_H #include #endif #endif #include #include "rpmfind.h" #include "transport.h" #include "autoupdate.h" #include "signatures.h" #include "database.h" #include "rpmdata.h" #include "rdf_api.h" #include "deps.h" #define MAX_SOLVE_RECURSION_DEP 6 #define MAX_PACKAGES_BATCHES 4 #define MAX_BATCH_CONFLICTS 15 #define MAX_SIMULTANEOUS_UPGRADE 5000 extern rpmdb myDb; int autoupgradeToInstall(const char *URL, const char *filename, int force); int autoupgradeFetch(const char *URL, const char *filename); typedef struct autoupgradeRename { const char *orig; const char *new; } autoupgradeRename; struct autoupgradeRename autoupgradeRenameList[] = { { "egcs", "gcc" }, { "egcs-c++", "gcc-c++" }, { "egcs-objc", "gcc-objc" }, { "jade", "openjade" }, { "ssh", "openssh" }, { "ssh-clients", "openssh-clients" }, { "ssh-server", "openssh-server" }, { "sawmill", "sawfish" }, { "sawmill-devel", "sawfish-devel" }, { NULL, NULL } }; /* */ char **autoupgradeURLList = NULL; int autoupgradeURLListLen = 0; int autoupgradeURLListMax = 0; typedef struct autoupgradeInfo autoupgradeInfo; typedef struct autoupgradeInfo *autoupgradeInfoPtr; struct autoupgradeInfo { char *url; /* what package is it related to */ int state; /* the status informations */ char *name; /* the package name */ char *version; /* the package version */ char *release; /* the package release */ int conflict; /* the package showed a conflict */ }; autoupgradeInfoPtr *autoupgradeHistory = NULL; int autoupgradeHistoryLen = 0; int autoupgradeHistoryMax = 0; #define RPM_AUTOUPGRADE_STATUS_DONE 1 #define RPM_AUTOUPGRADE_STATUS_TODO 2 #define RPM_AUTOUPGRADE_STATUS_OLD 3 #define RPM_AUTOUPGRADE_STATUS_SKIPPED 4 #define RPM_AUTOUPGRADE_STATUS_ARCH 5 #define RPM_AUTOUPGRADE_STATUS_BROKEN 6 /* * We build a transationSet containing all the updates we expect to * launch. The goal is to manage to check beforehand problems in the final * RPM command and fetch extra packages possibly needed for the update. * Some packages may be dropped from the update if we cannot manage to * satify all their dependancies or if they conflict with installed * packages. */ int autoupgradeLen = 0; char* autoupgradeName[MAX_SIMULTANEOUS_UPGRADE]; char* autoupgradeVersion[MAX_SIMULTANEOUS_UPGRADE]; char* autoupgradeRelease[MAX_SIMULTANEOUS_UPGRADE]; int autoupgradeDrop[MAX_SIMULTANEOUS_UPGRADE]; int autoupgradeConflict[MAX_SIMULTANEOUS_UPGRADE]; Header autoupgradeHeaders[MAX_SIMULTANEOUS_UPGRADE]; char* autoupgradeFiles[MAX_SIMULTANEOUS_UPGRADE]; int autoupgradeNbConflicts = 0; /* * autoupgradeSwap: * * swap 2 entries in the lists */ void autoupgradeSwap(int i, int j) { int tmp; char *temp; Header h; if ((i < 0) || (i >= autoupgradeLen)) return; if ((j < 0) || (j >= autoupgradeLen)) return; temp = autoupgradeName[i]; autoupgradeName[i] = autoupgradeName[j]; autoupgradeName[j] = temp; temp = autoupgradeVersion[i]; autoupgradeVersion[i] = autoupgradeVersion[j]; autoupgradeVersion[j] = temp; temp = autoupgradeRelease[i]; autoupgradeRelease[i] = autoupgradeRelease[j]; autoupgradeRelease[j] = temp; temp = autoupgradeFiles[i]; autoupgradeFiles[i] = autoupgradeFiles[j]; autoupgradeFiles[j] = temp; h = autoupgradeHeaders[i]; autoupgradeHeaders[i] = autoupgradeHeaders[j]; autoupgradeHeaders[j] = h; tmp = autoupgradeDrop[i]; autoupgradeDrop[i] = autoupgradeDrop[j]; autoupgradeDrop[j] = tmp; tmp = autoupgradeConflict[i]; autoupgradeConflict[i] = autoupgradeConflict[j]; autoupgradeConflict[j] = tmp; } #if 0 /* * autoupgradeCheckDepends: * * Check if the first package has dependancies provided by * the second. */ int autoupgradeCheckDepends(int package, int provider) { int val, i, j; int_32 count, type; void * provides = NULL; val = getTagNumber("RPMTAG_PROVIDES"); if (!headerGetEntry(autoupgradeHeaders[provider], val, &type, &prov, &nbprov) || !nbprov) { return(0); } val = getTagNumber("RPMTAG_REQUIRENAME"); if (!headerGetEntry(h, val, &type, &p, &count) || !p) { } #endif /* * autoupgradeGetRename: * * Get the possible package name this package is expected to replace */ const char * autoupgradeGetRename(const char *package) { int i; for (i = 0;;i++) { if (autoupgradeRenameList[i].new == NULL) return(NULL); if (!strcmp(autoupgradeRenameList[i].new, package)) return(autoupgradeRenameList[i].orig); } return(NULL); } /* * autoupgradeShouldAttemptFirst: * * should we try to install such a package by default */ int autoupgradeShouldAttemptFirst(const char *name) { int res = 0; if ((!strncmp(name, "libc-", 5)) || (!strncmp(name, "glibc-", 6)) || (!strncmp(name, "libstdc", 7)) || (!strncmp(name, "initscript", 10)) || (!strncmp(name, "gcc", 3)) || (!strncmp(name, "cpp", 3)) || (!strncmp(name, "binutils", 8)) || (!strncmp(name, "egcs", 4)) || (!strncmp(name, "db", 2)) || (!strncmp(name, "sh-", 3)) || (!strncmp(name, "bzip", 4)) || (!strncmp(name, "rpm-", 4)) || (!strncmp(name, "pam-", 4)) || (!strncmp(name, "shadow-", 7)) || (!strncmp(name, "bash-", 5)) || (!strncmp(name, "bash2-", 6)) || (!strncmp(name, "XFree86-", 8)) || (!strncmp(name, "readline", 8)) || (!strncmp(name, "ncurses", 7))) res = 1; if (!res) return(0); return(res); } /* * autoupgradeShouldForce: * * should we try to install such a package by default */ int autoupgradeShouldForce(const char *name) { int res = 0; if ((!strncmp(name, "libc-", 5)) || (!strncmp(name, "glibc-", 6)) || (!strncmp(name, "libstdc", 7)) || (!strncmp(name, "db", 2)) || (!strncmp(name, "sh-", 3)) || (!strncmp(name, "bzip", 4)) || (!strncmp(name, "rpm-", 4)) || (!strncmp(name, "pam-", 4)) || (!strncmp(name, "shadow-", 7)) || (!strncmp(name, "bash-", 5)) || (!strncmp(name, "readline", 8)) || (!strncmp(name, "ncurses", 7))) res = 1; if (!res) return(0); if (strstr(name, "-devel")) return(1); return(res); } /* * autoupgradeAddURL: * * Add an URL to the list of autoupgrade repository */ void autoupgradeAddURL(const char *URL) { int i; for (i = 0;i < autoupgradeURLListLen;i++) { if (!strcmp(URL, autoupgradeURLList[i])) { return; } } if (autoupgradeURLList == NULL) { autoupgradeURLListMax = 20; autoupgradeURLList = malloc(autoupgradeURLListMax * sizeof(autoupgradeInfoPtr)); if (autoupgradeURLList == NULL) { fprintf(stderr, "autoupgradeAddURLList: memory allocation error\n"); exit(1); } } if (autoupgradeURLListLen >= autoupgradeURLListMax) { autoupgradeURLListMax *= 2; autoupgradeURLList = realloc(autoupgradeURLList, autoupgradeURLListMax * sizeof(char *)); if (autoupgradeURLList == NULL) { fprintf(stderr, "autoupgradeAddURLList: memory allocation error\n"); exit(1); } } if (rpmfindVerbose > 1) printf("autoupgradeAddURLList: %s added\n", URL); autoupgradeURLList[autoupgradeURLListLen++] = strdup(URL); } /* * autoupgradeCheckHistory: * * Check an URL against the autoupgradeHistory * Returns the autoupgradeInfoPtr or NULL if not found */ autoupgradeInfoPtr autoupgradeCheckHistory(const char *URL) { int i; if (URL == NULL) return(NULL); for (i = 0;i < autoupgradeHistoryLen;i++) { if (!strcmp(URL, autoupgradeHistory[i]->url)) return(autoupgradeHistory[i]); } return(NULL); } /* * autoupgradeAddHistory: * * Add an URL in the autoupgradeHistory */ void autoupgradeAddHistory(const char *URL, int state, const char *name, const char *version, const char *release) { int i; autoupgradeInfoPtr info; for (i = 0;i < autoupgradeHistoryLen;i++) { if (!strcmp(URL, autoupgradeHistory[i]->url)) { if (rpmfindVerbose) { if (autoupgradeHistory[i]->state != state) { printf("autoupgradeAddHistory: %s state changed to ", URL); switch (state) { case RPM_AUTOUPGRADE_STATUS_DONE: printf("DONE\n"); break; case RPM_AUTOUPGRADE_STATUS_TODO: printf("TODO\n"); break; case RPM_AUTOUPGRADE_STATUS_OLD: printf("OLD\n"); break; case RPM_AUTOUPGRADE_STATUS_SKIPPED: printf("SKIPPED\n"); break; case RPM_AUTOUPGRADE_STATUS_ARCH: printf("ARCH\n"); break; case RPM_AUTOUPGRADE_STATUS_BROKEN: printf("ARCH\n"); break; default: printf("%d ???\n", state); break; } } } autoupgradeHistory[i]->state = state; return; } } if (autoupgradeHistory == NULL) { autoupgradeHistoryMax = 200; autoupgradeHistory = malloc(autoupgradeHistoryMax * sizeof(autoupgradeInfoPtr)); if (autoupgradeHistory == NULL) { fprintf(stderr, "autoupgradeAddHistory: memory allocation error\n"); exit(1); } } if (autoupgradeHistoryLen >= autoupgradeHistoryMax) { autoupgradeHistoryMax *= 2; autoupgradeHistory = realloc(autoupgradeHistory, autoupgradeHistoryMax * sizeof(autoupgradeInfoPtr)); if (autoupgradeHistory == NULL) { fprintf(stderr, "autoupgradeAddHistory: memory allocation error\n"); exit(1); } } if (rpmfindVerbose > 1) printf("autoupgradeAddHistory: %s added\n", URL); info = (autoupgradeInfoPtr) malloc(sizeof(autoupgradeInfo)); if (info == NULL) { fprintf(stderr, "autoupgradeAddHistory: memory allocation error\n"); exit(1); } info->url = strdup(URL); info->state = state; info->name = strdup(name); info->version = strdup(version); info->release = strdup(release); info->conflict = 0; autoupgradeHistory[autoupgradeHistoryLen++] = info; } /* * autoupgradeLoadHistory: * * Load the autoupgrade history consisting of all the URL * of the updates previously applied */ void autoupgradeLoadHistory(void) { FILE *input; struct stat statbuf; int uid; int line = 0; char path[400]; char linebuf[1000]; char url[1000]; char name[200]; char version[200]; char release[200]; int value; snprintf(path, sizeof(path), "%s/autoupgradeHistory", rpmfindTempDir); if (stat(path, &statbuf)) goto fail; uid = getuid(); if ((statbuf.st_uid != 0) && (statbuf.st_uid != uid)) goto fail; if (statbuf.st_mode & 0x0022) goto fail; if (autoupgradeHistory != NULL) return; input = fopen (path, "r"); if (input == NULL) { fprintf (stderr, "Cannot read history from %s :\n", path); perror ("fopen failed"); return; } if (rpmfindVerbose > 1) printf("autoupgradeLoadHistory(%s)\n", path); while (1) { /* * read one line in string buffer. */ if (fgets (&linebuf[0], sizeof (linebuf) - 1, input) == NULL) break; line++; if (sscanf(linebuf, "%d %s %s %s %s", &value, name, version, release, url) == 5) { autoupgradeAddHistory(url, value, name, version, release); } else { fprintf (stderr, "corrupted line %d in %s\n", line, path); continue; } } fclose(input); return; fail: fprintf (stderr, "Cannot read history from %s :\n", path); unlink(path); } /* * autoupgradeSaveHistory: * * Save the autoupgrade history consisting of all the URL * of the updates previously applied */ void autoupgradeSaveHistory(void) { FILE *output; char path[400]; int i; snprintf(path, sizeof(path), "%s/autoupgradeHistory", rpmfindTempDir); if (autoupgradeHistory == NULL) { unlink(path); return; } output = fopen(path, "w"); if (output == NULL) { fprintf (stderr, "Cannot write history to %s :\n", path); return; } for (i = 0;i < autoupgradeHistoryLen;i++) { fprintf(output, "%d %s %s %s %s\n", autoupgradeHistory[i]->state, autoupgradeHistory[i]->name, autoupgradeHistory[i]->version, autoupgradeHistory[i]->release, autoupgradeHistory[i]->url); } fclose(output); } /* * autoupgradeLookupDep: * @name: the package name * @flags: extra version flags * @version: extra version value if any * @release: extra release value if any * * Try to find a package providing a given missing dependancy. * We first look in the history list, since this probably available * as an update too, then we do a strict lookup in the general * rpmfind database. If we find the corresponding package it * is added in the upgrade list. * * Returns 1 in case of success, 0 if lookup failed, -1 in case of error */ int autoupgradeLookupDep(const char *name, int flags, const char *version, const char *release) { rdfSchema rdf; rdfNamespace rpmNs; rdfNamespace rdfNs; rdfDescription desc; char *value; int i, res; char *filename; char url[1000]; char *package; int candidate = -1; for (i = 0;i < autoupgradeLen;i++) { if (!strcmp(name, autoupgradeName[i])) return(1); } if (rpmfindVerbose) { printf("autoupgradeLookupDep: %s ", name); if (flags) { printf(" "); if (flags & RPMSENSE_LESS) printf("<"); if (flags & RPMSENSE_GREATER) printf(">"); if (flags & RPMSENSE_EQUAL) printf("="); if (flags & RPMSENSE_SERIAL) printf("S"); printf(" %s", version); } printf("\n"); } if (rpmNoAutoUpgradeCheck(name)) { if (rpmfindVerbose) { printf("Dropping package %s : no autoupgrade\n", name); } return(0); } /* * Check then in the history, progressing backward to try to * locate the most recent entry */ for (i = autoupgradeHistoryLen - 1;i >= 0 ;i--) { if (!strcmp(name, autoupgradeHistory[i]->name)) { candidate = i; if (flags) { res = rpmFindCompareVersions(autoupgradeHistory[i]->version, version); if ((res == 0) && (rpmfindCheckRelease == 1)) { res = rpmFindCompareVersions( autoupgradeHistory[i]->release, release); } if ((flags & RPMSENSE_LESS) && (res >= 0)) continue; else if ((flags & RPMSENSE_LESS) && (flags & RPMSENSE_EQUAL) && (res > 0)) continue; else if ((flags & RPMSENSE_GREATER) && (res <= 0)) continue; else if ((flags & RPMSENSE_GREATER) && (flags & RPMSENSE_EQUAL) && (res < 0)) continue; else if ((flags & RPMSENSE_EQUAL) && (res != 0)) continue; else if (res != 0) continue; } /* * ask to install that file. */ strncpy(url, autoupgradeHistory[i]->url, (sizeof(url) - 1)); url[sizeof(url) - 1] = 0; filename = &url[strlen(url)]; while ((filename > url) && (*filename != '/')) filename--; if (*filename == '/') { *filename = 0; filename++; } autoupgradeFetch(url, filename); autoupgradeToInstall(url, filename, 1); return(1); } } if (candidate != -1) { /* * ask to install that file. */ strncpy(url, autoupgradeHistory[candidate]->url, (sizeof(url) - 1)); url[sizeof(url) - 1] = 0; filename = &url[strlen(url)]; while ((filename > url) && (*filename != '/')) filename--; if (*filename == '/') { *filename = 0; filename++; } autoupgradeFetch(url, filename); autoupgradeToInstall(url, filename, 1); return(1); } /* * Ok this is probably a resource name dependancy, ot a package name * dependancy, try to find the packages exporting this resource */ filename = rpmFetchResource(name); if (filename == NULL) { if (rpmfindVerbose) printf("Error fetching %s metadata\n", name); return(0); } rdf = rdfRead(filename); unlink(filename); if (rdf == NULL) return(0); /* * Start the analyze, check that's an RDF for RPM packages. */ rdfNs = rdfGetNamespace(rdf, "http://www.w3.org/1999/02/22-rdf-syntax-ns#"); if (rdfNs == NULL) { rdfNs = rdfGetNamespace(rdf, "http://www.w3.org/TR/WD-rdf-syntax#"); if (rdfNs == NULL) { if (rpmfindVerbose) printf("%s is not an RDF schema\n", filename); rdfDestroySchema(rdf); return(0); } } rpmNs = rdfGetNamespace(rdf, "http://www.rpm.org/"); if (rdfNs == NULL) { if (rpmfindVerbose) printf("%s is not an RPM specific RDF schema\n", filename); rdfDestroySchema(rdf); return(0); } desc = rdfFirstDescription(rdf); if (rdfNs == NULL) { if (rpmfindVerbose) printf("%s RDF schema seems empty\n", filename); rdfDestroySchema(rdf); return(0); } /* * We are pretty sure that it will be a valid schema, * Walk the tree and collect the packages descriptions. */ while (desc != NULL) { /* * extract the package Name metadata informations */ rdfGetValue(desc, "Name", rpmNs, &value, NULL); if (value != NULL) package = value; else { if (rpmfindVerbose) printf("%s RDF schema invalid : no Name\n", filename); rdfDestroySchema(rdf); return(0); } /* * Estimate whether such package should be looked for * Then do a recursive lookup. */ if (strcmp(package, name)) { res = autoupgradeLookupDep(package, 0, NULL, NULL); /* * If successful, try to keep this package. */ if (res == 1) { rdfDestroySchema(rdf); free(package); return(1); } } /* * Skip to next Description in the RDf file. */ free(package); desc = rdfNextDescription(desc); } /* * Cleanup. */ rdfDestroySchema(rdf); return(0); } /* * autoupgradeCheckSignature: * @package: path to a package on the local filesystem * * Check the package against it's PGP (or other method) signature * * Returns 1 in case of success, 0 if check failed, -1 in case of error */ int autoupgradeCheckSignature(const char *package) { if (rpmfindVerbose) printf("autoupgradeCheckSignature: unimplemented\n"); /* * TODO !!!! * use verifySignature, or simply rpm --checksig() ??? */ return(1); } /* * autoupgradeCheckExist: * @filename: path to a package on the local filesystem * * Verify that the current file exists, is a valid rpm and * check that the package is owned by the current id and could * not have been tampered by another user (except root) * * Returns 1 in case of success, 0 if check failed, -1 in case of error */ int autoupgradeCheckExist(const char *filename) { struct stat statbuf; int uid; #if defined(HAVE_RPM_RPMIO_H) FD_t fd; #else int fd; #define fdOpen(_a, _b, _c) open((_a), (_b)) #define fdClose(_a) close(_a) #endif int rc; Header h = NULL; int isSource; if (stat(filename, &statbuf)) goto fail; uid = getuid(); if ((statbuf.st_uid != 0) && (statbuf.st_uid != uid)) goto fail; if (statbuf.st_mode & 0x0022) goto fail; if (statbuf.st_size <= 500) goto fail; /* * Try to open the header. */ #if defined(USE_RPMIO) fd = Fopen(filename, "r.fdio"); if (fd == NULL || Ferror(fd)) goto fail; #else if ((fd = fdOpen(filename, O_RDONLY, 0)) < 0) goto fail; #endif rc = rpmReadPackageHeader(fd, &h, &isSource, NULL, NULL); if (rc != 0) goto fail; if (!h) { #if defined(USE_RPMIO) Fclose(fd); #else fdClose(fd); #endif goto fail; } headerFree(h); #if defined(USE_RPMIO) Fclose(fd); #else fdClose(fd); #endif return(1); fail: /* unlink(filename); */ return(0); } /* * autoupgradeBuildDirList: * @URL: the URL where to find updated packages * * Build the list of files found at the URL * Should this be recursive ??? * * Returns a NULL terminated array of pointer to file names */ char ** autoupgradeBuildDirList(const char *URL) { char **ret; if (URL == NULL) return(NULL); if (rpmfindVerbose) printf("autoupgradeBuildDirList: %s\n", URL); ret = buildDirList(URL, 0); return(ret); } /* * autoupgradeFetch: * @URL: the URL of the location * @filename: the filename * * Fetch the given package * * Returns 0 or -1 in case of error */ int autoupgradeFetch(const char *URL, const char *filename) { char url[2000]; char path[2000]; snprintf(path, sizeof(path), "%s/%s", rpmfindTempDir, filename); snprintf(url, sizeof(url), "%s/%s", URL, filename); if (autoupgradeCheckExist(path) <= 0) { if (fetchURLToFile(url, path) < 0) { fprintf(stderr,"autoupgradeFetch: could not fetch %s\n", url); return(-1); } else { if (rpmfindVerbose) printf("autoupgradeFetch: fetched %s to %s\n", url, path); } } return(0); } /* * autoupgradeGuessInfo: * @URL: the URL of the location * @name: the package name * @version: the package version * @release: the package release * @arch: the package arch * * Try to guess from the URL the name, version, release and architecture * of a given package. * * Returns 1 in case of success, 0 if this could not be guessed, -1 in case * of error. In case of success name, version, release and arch are * updated with constant strings, user will need to copy those. */ int autoupgradeGuessInfo(const char *URL, const char **name, const char **version, const char **release, const char **arch) { static char buffer[1000]; char *cur; char *baseA, *baseB, *baseC, *baseD, *baseE; /* * Do a local copy, removing the path. */ strncpy(buffer, URL, (sizeof(buffer) - 1)); buffer[sizeof(buffer) - 1] = 0; cur = &buffer[strlen(buffer)]; while ((cur > buffer) && (*cur != '/')) cur--; if (*cur == '/') { *cur = 0; cur++; } /* * Now split package/version/releaseetc, the separators are '-' now. */ baseA = cur; baseD = NULL; baseE = NULL; while (*cur != 0) { while ((*cur != 0) && (*cur != '-')) cur++; if (*cur == 0) break; baseD = baseE; baseE = cur; cur++; } if ((baseD == NULL) || (baseE == NULL)) return(0); *baseD = 0; baseD++; *baseE = 0; baseE++; *name = baseA; *version = baseD; *release = baseE; /* * Split onto baseA baseB baseC using '.' as delimiter. */ cur = baseE; baseB = NULL; baseC = NULL; while (*cur != 0) { while ((*cur != 0) && (*cur != '.')) cur++; if (*cur == 0) break; baseB = baseC; baseC = cur; cur++; } if ((baseB == NULL) || (baseC == NULL)) return(0); *baseB = 0; baseB++; *baseC = 0; baseC++; /* * We expect baseC to point to "rpm" */ if (strcmp(baseC, "rpm")) return(0); /* * We expect baseB to be the architecture. */ if (strlen(baseB) > 7) return(0); /* @@ any other useful check ? */ *arch = baseB; return(1); } #define ENTRY_CLEANUP(p) \ if ((type == RPM_STRING_ARRAY_TYPE || type == RPM_I18NSTRING_TYPE)&&\ (p != NULL)) { free((p)); p = NULL; } /* * autoupgradeToInstall: * @URL: the URL of the location * @filename: the filename * @force: force the tests * * Check wether that resource should be installed: * basically it applies if: * - it's not in the existing history * - a similar resource is installed * - the resource has a release number inferior to the current one * * Returns 0 or 1 if should be installed, and -1 in case of error */ int autoupgradeToInstall(const char *URL, const char *filename, int force) { char url[2000]; char path[2000]; struct stat statbuf; #if defined(HAVE_RPM_RPMIO_H) FD_t fd = NULL; #else int fd = -1; #define fdOpen(_a, _b, _c) open((_a), (_b)) #define fdClose(_a) close(_a) #endif int rc; Header h = NULL; Header ih = NULL; #ifdef USE_RPMIO const char * name = NULL, * version = NULL, * release = NULL, * arch = NULL; const char *iname = NULL, *iversion = NULL, *irelease = NULL; #else const char * name = NULL, * version = NULL, * release = NULL, * arch = NULL; const char *iname = NULL, *iversion = NULL, *irelease = NULL; dbiIndexSet matches; #endif int found = 0, cmp = 0, i; int_32 count, type; int isSource; autoupgradeInfoPtr info; int toInstall; const char *thename; snprintf(path, sizeof(path), "%s/%s", rpmfindTempDir, filename); snprintf(url, sizeof(url), "%s/%s", URL, filename); i = strlen(filename); if ((i <= 4) || ((strcmp(&filename[i - 4], ".rpm")) && (strcmp(&filename[i - 4], ".RPM")))) { return(0); } if ((i >= 9) && (!strcmp(&filename[i - 8], ".src.rpm"))) { return(0); } if ((URL == NULL) || (filename == NULL)) { if (rpmfindVerbose) { if (URL == NULL) printf("autoupgradeToInstall: URL == NULL\n"); if (filename == NULL) printf("autoupgradeToInstall: filename == NULL\n"); } return(-1); } if (rpmfindVerbose > 1) printf("autoupgradeToInstall: %s, %s\n", URL, filename); /* * Check if it's in the history */ info = autoupgradeCheckHistory(url); if (info != NULL) { if (!force) { switch (info->state) { case RPM_AUTOUPGRADE_STATUS_ARCH: if (rpmfindVerbose) printf("%s wrong arch: skipped\n", url); return(0); case RPM_AUTOUPGRADE_STATUS_BROKEN: if (rpmfindVerbose) printf("%s tagged broken: skipped\n", url); return(0); case RPM_AUTOUPGRADE_STATUS_OLD: if (rpmfindVerbose) printf("%s marked OLD: skipped\n", url); return(0); case RPM_AUTOUPGRADE_STATUS_DONE: if (rpmfindVerbose) printf("%s marked DONE: checking anyway\n", url); break; case RPM_AUTOUPGRADE_STATUS_TODO: if (rpmfindVerbose) printf("%s marked TODO: checking\n", url); break; case RPM_AUTOUPGRADE_STATUS_SKIPPED: if (rpmfindVerbose) printf("%s marked SKIPPED: checking\n", url); break; default: fprintf(stderr, "%s has stange history state\n", url); break; } } name = info->name; version = info->version; release = info->release; if (rpmNoAutoUpgradeCheck(name)) { return(0); } } else if (autoupgradeGuessInfo(url, &name, &version, &release, &arch)) { if (rpmNoAutoUpgradeCheck(name)) { return(0); } } else { if (rpmfindVerbose) printf("%s not in history: checking\n", url); /* * otherwise load it locally for scrutiny */ if (autoupgradeFetch(URL, filename) < 0) { printf("Failed to load %s/%s to %s\n", URL, filename, path); return(-1); } if (stat(path, &statbuf)) { printf("%s seems lost\n", URL); return(-1); } /* * Try to open the header. */ #if defined(USE_RPMIO) fd = Fopen(path, "r.fdio"); if (fd == NULL || Ferror(fd)) { printf("Failed to open RPM %s\n", path); autoupgradeAddHistory(url, RPM_AUTOUPGRADE_STATUS_BROKEN, "unknown", "unknown", "unknown"); return(-1); } #else if ((fd = fdOpen(path, O_RDONLY, 0)) < 0) { printf("Failed to open RPM %s\n", path); autoupgradeAddHistory(url, RPM_AUTOUPGRADE_STATUS_BROKEN, "unknown", "unknown", "unknown"); return(-1); } #endif rc = rpmReadPackageHeader(fd, &h, &isSource, NULL, NULL); if (rc != 0) { printf("Failed to read RPM header of %s\n", path); autoupgradeAddHistory(url, RPM_AUTOUPGRADE_STATUS_BROKEN, "unknown", "unknown", "unknown"); #if defined(USE_RPMIO) Fclose(fd); #else fdClose(fd); #endif return(-1); } if (!h) { #if defined(USE_RPMIO) Fclose(fd); #else fdClose(fd); #endif return(-1); } /* extract informations from the header */ headerGetEntry(h, RPMTAG_NAME, &type, (void **) &name, &count); if (name == NULL) { if (rpmfindVerbose) printf("Invalid package %s : no name\n", path); autoupgradeAddHistory(url, RPM_AUTOUPGRADE_STATUS_BROKEN, "unknown", "unknown", "unknown"); headerFree(h); #if defined(USE_RPMIO) Fclose(fd); #else fdClose(fd); #endif return(-1); } headerGetEntry(h, RPMTAG_VERSION, &type, (void **) &version, &count); if ((version == NULL) || (version[0] == 0)) { if (rpmfindVerbose) printf("Invalid package %s : version invalid\n", path); autoupgradeAddHistory(url, RPM_AUTOUPGRADE_STATUS_BROKEN, name, "unknown", "unknown"); headerFree(h); #if defined(USE_RPMIO) Fclose(fd); #else fdClose(fd); #endif return(-1); } headerGetEntry(h, RPMTAG_RELEASE, &type, (void **) &release, &count); if ((release == NULL) || (release[0] == 0)) { if (rpmfindVerbose) printf("Invalid package %s : release invalid\n", path); autoupgradeAddHistory(url, RPM_AUTOUPGRADE_STATUS_BROKEN, name, version, "unknown"); headerFree(h); #if defined(USE_RPMIO) Fclose(fd); #else fdClose(fd); #endif return(-1); } if (isSource) { if (rpmfindVerbose) printf("package %s is a source package, skipped\n", path); autoupgradeAddHistory(url, RPM_AUTOUPGRADE_STATUS_ARCH, name, version, release); headerFree(h); #if defined(USE_RPMIO) Fclose(fd); #else fdClose(fd); #endif return(0); } headerGetEntry(h, RPMTAG_ARCH, &type, (void **) &arch, &count); if ((arch == NULL) || (arch[0] == 0)) { if (rpmfindVerbose) printf("Invalid package %s : arch invalid\n", path); autoupgradeAddHistory(url, RPM_AUTOUPGRADE_STATUS_BROKEN, name, version, release); headerFree(h); #if defined(USE_RPMIO) Fclose(fd); #else fdClose(fd); #endif return(-1); } if (rpmNoAutoUpgradeCheck(name)) { if (rpmfindVerbose) printf("Skipping package %s : no autoupgrade\n", path); autoupgradeAddHistory(url, RPM_AUTOUPGRADE_STATUS_SKIPPED, name, version, release); headerFree(h); fdClose(fd); return(0); } if (strcmp(myArch, arch)) { if ((arch[0] == 'i') && (arch[2] == '8') && (arch[3] == '6') && (myArch[0] == 'i') && (myArch[2] == '8') && (myArch[3] == '6')){ int noArch; int noMyArch; noArch = arch[1] - '0'; noMyArch = myArch[1] - '0'; switch (noArch) { case 3: case 4: /* i386 set is compatible with full line */ break; case 5: case 6: /* 585 and 686 should be compatible */ if (noMyArch >= 5) break; default: if (rpmfindVerbose) printf("package %s is for arch %s, skipped\n", path, arch); autoupgradeAddHistory(url, RPM_AUTOUPGRADE_STATUS_ARCH, name, version, release); headerFree(h); #if defined(USE_RPMIO) Fclose(fd); #else fdClose(fd); #endif return(0); } } else if (strcmp(arch, "noarch")) { if (rpmfindVerbose) printf("package %s is for arch %s, skipped\n", path, arch); autoupgradeAddHistory(url, RPM_AUTOUPGRADE_STATUS_ARCH, name, version, release); headerFree(h); #if defined(USE_RPMIO) Fclose(fd); #else fdClose(fd); #endif return(0); } } } thename = name; recheck_replace: /* * Now we can check whether updating applies * List all the packages */ #ifdef USE_RPMIO { rpmdbMatchIterator mi; Header myih; mi = rpmdbInitIterator(myDb, RPMTAG_PROVIDENAME, thename, 0); if (mi) { if (rpmfindVerbose > 1) printf("Resource %s is provided by:", thename); while ((myih = rpmdbNextIterator(mi)) != NULL) { /* XXX preserve the last header's memory references in ih */ if (ih) headerFree(ih); ih = headerLink(myih); headerNVR(ih, &iname, &iversion, &irelease); if (rpmfindVerbose > 1) printf(" %s-%s-%s\n", iname, iversion, irelease); found = 1; cmp = rpmFindCompareVersions(version, iversion); if ((cmp == 0) && (rpmfindCheckRelease == 1)) { cmp = rpmFindCompareVersions(release, irelease); } if (cmp >= 0) break; } } rpmdbFreeIterator(mi); } #else /* USE_RPMIO */ if (rpmdbFindByProvides(myDb, thename, &matches) == 0) { int j; /* * If matches.count > 1 there is more than one package provinding * the given resource. We need to check for more than one */ if (rpmfindVerbose > 1) printf("Resource %s is provided by:", thename); for (j = 0; j < matches.count; j++) { if (matches.recs[j].recOffset) { ih = rpmdbGetRecord(myDb, matches.recs[j].recOffset); if (!ih) { fprintf(stderr, "error: could not read database record\n"); } else { headerGetEntry(ih, RPMTAG_NAME, &type, (void **) &iname, &count); headerGetEntry(ih, RPMTAG_VERSION, &type, (void **) &iversion, &count); headerGetEntry(ih, RPMTAG_RELEASE, &type, (void **) &irelease, &count); if (rpmfindVerbose > 1) printf(" %s-%s-%s\n", iname, iversion, irelease); found = 1; cmp = rpmFindCompareVersions(version, iversion); if ((cmp == 0) && (rpmfindCheckRelease == 1)) { cmp = rpmFindCompareVersions(release, irelease); } if (cmp >= 0) break; } } } dbiFreeIndexRecord(matches); } #endif /* USE_RPMIO */ if (ih == NULL) /* Keep looking? */ #ifdef USE_RPMIO { rpmdbMatchIterator mi; Header myih; mi = rpmdbInitIterator(myDb, RPMDBI_LABEL, thename, 0); if (mi == NULL) { if (rpmfindVerbose) printf("Resource %s not installed\n", thename); } else { if (rpmfindVerbose) printf("Package %s is installed:", thename); while ((myih = rpmdbNextIterator(mi)) != NULL) { /* XXX preserve the last header's memory references in ih */ if (ih) headerFree(ih); ih = headerLink(myih); headerNVR(ih, &iname, &iversion, &irelease); if (rpmfindVerbose) printf(" %s-%s-%s", iname, iversion, irelease); found = 1; } if (found && rpmfindVerbose) printf("\n"); } rpmdbFreeIterator(mi); } #else /* USE_RPMIO */ { int res; res = rpmdbFindByLabel(myDb, thename, &matches); if (res == 1) { if (rpmfindVerbose) printf("Resource %s not installed\n", thename); } else if (res == 2) { if (rpmfindVerbose) printf("Error looking for package %s\n", thename); } else { int j; /* * If matches.count > 1 there is more than one package provinding * the given resource. We need to check for more than one */ if (rpmfindVerbose > 1) printf("Package %s is installed:", thename); for (j = 0; j < matches.count; j++) { if (matches.recs[j].recOffset) { ih = rpmdbGetRecord(myDb, matches.recs[j].recOffset); if (!ih) { fprintf(stderr, "error: could not read database record\n"); } else { /* extract informations from the header */ headerGetEntry(ih, RPMTAG_NAME, &type, (void **) &iname, &count); headerGetEntry(ih, RPMTAG_VERSION, &type, (void **) &iversion, &count); headerGetEntry(ih, RPMTAG_RELEASE, &type, (void **) &irelease, &count); if (rpmfindVerbose > 1) printf(" %s-%s-%s\n", iname, iversion, irelease); found = 1; cmp = rpmFindCompareVersions(version, iversion); if ((cmp == 0) && (rpmfindCheckRelease == 1)) { cmp = rpmFindCompareVersions(release, irelease); } if (cmp >= 0) break; } } } if (rpmfindVerbose > 1) printf("\n"); dbiFreeIndexRecord(matches); } } #endif /* USE_RPMIO */ if (!found) { if (!strcmp(thename, name)) { thename = autoupgradeGetRename(name); if (thename != NULL) goto recheck_replace; } if (!force) { /* * the file should be marked skipped but not forever * in case the given module is being added later on the system */ autoupgradeAddHistory(url, RPM_AUTOUPGRADE_STATUS_SKIPPED, name, version, release); } } else if ((strcmp(thename, name)) && found) { /* a replacement forces the upgrade even if the version is lower */ cmp = 1; } else { /* * Compare the versions */ if ((h != NULL) && (ih != NULL)) cmp = rpmVersionCompare(h, ih); else { cmp = rpmFindCompareVersions(version, iversion); if ((cmp == 0) && (rpmfindCheckRelease == 1)) { cmp = rpmFindCompareVersions(release, irelease); } } if (cmp == 0) { autoupgradeAddHistory(url, RPM_AUTOUPGRADE_STATUS_DONE, name, version, release); force = 0; } else if (cmp < 0) { autoupgradeAddHistory(url, RPM_AUTOUPGRADE_STATUS_OLD, name, version, release); force = 0; } else { /* * Check against duplicate updates of the same package * mark the next ones skipped but don't unlink the * packages, it will be reused next run. */ for (i = 0;i < autoupgradeHistoryLen;i++) { if ((autoupgradeHistory[i] != info) && (!strcmp(autoupgradeHistory[i]->name, name)) && (autoupgradeHistory[i]->state == RPM_AUTOUPGRADE_STATUS_TODO)) { autoupgradeAddHistory(url, RPM_AUTOUPGRADE_STATUS_SKIPPED, name, version, release); if (rpmfindVerbose) printf("New run may be needed for %s-%s-%s\n", name, version, release); headerFree(ih); if (h != NULL) { headerFree(h); #if defined(USE_RPMIO) Fclose(fd); #else fdClose(fd); #endif } return(0); } } if (i >= autoupgradeHistoryLen) autoupgradeAddHistory(url, RPM_AUTOUPGRADE_STATUS_TODO, name, version, release); } } /* * Register that package for upgrade if cmp > 0 * Saving of informations for further analysis */ if ((h == NULL) && ((cmp > 0) || (force))) { /* * Load the package for the header check */ if (autoupgradeFetch(URL, filename) < 0) { printf("Failed to load %s/%s to %s\n", URL, filename, path); return(-1); } if (stat(path, &statbuf)) { printf("%s seems lost\n", URL); return(-1); } /* * Try to open the header. */ #if defined(USE_RPMIO) fd = Fopen(path, "r.fdio"); if (fd == NULL || Ferror(fd)) { printf("Failed to open RPM %s\n", path); autoupgradeAddHistory(url, RPM_AUTOUPGRADE_STATUS_BROKEN, "unknown", "unknown", "unknown"); return(-1); } #else if ((fd = fdOpen(path, O_RDONLY, 0)) < 0) { printf("Failed to open RPM %s\n", path); autoupgradeAddHistory(url, RPM_AUTOUPGRADE_STATUS_BROKEN, "unknown", "unknown", "unknown"); return(-1); } #endif rc = rpmReadPackageHeader(fd, &h, &isSource, NULL, NULL); if (rc != 0) { printf("Failed to read RPM header of %s\n", path); autoupgradeAddHistory(url, RPM_AUTOUPGRADE_STATUS_BROKEN, "unknown", "unknown", "unknown"); #if defined(USE_RPMIO) Fclose(fd); #else fdClose(fd); #endif return(-1); } if (!h) { #if defined(USE_RPMIO) Fclose(fd); #else fdClose(fd); #endif return(-1); } #if defined(USE_RPMIO) Fclose(fd); #else fdClose(fd); #endif /* * Do an ultimate check using rpmlib procvided function. */ if (!force) cmp = rpmVersionCompare(h, ih); } if ((cmp > 0) || (force)) { autoupgradeFiles[autoupgradeLen] = strdup(path); autoupgradeHeaders[autoupgradeLen] = h; autoupgradeName[autoupgradeLen] = strdup(name); autoupgradeVersion[autoupgradeLen] = strdup(version); autoupgradeRelease[autoupgradeLen] = strdup(release); autoupgradeDrop[autoupgradeLen] = 0; autoupgradeConflict[autoupgradeLen] = 0; autoupgradeLen++; } /* * Cleanup */ if ((h != NULL) && ((cmp <= 0) && (!force))) { headerFree(h); } if (found) { headerFree(ih); } /* * Check the signature of the downloaded file */ toInstall = (cmp > 0) || (force); if (toInstall) { if (stat(path, &statbuf)) { printf("%s seems lost\n", URL); return(-1); } if (!rpmfindCheckRPMSignature(path)) { /* * If we are paranoid, drop the package */ if (rpmfindParanoid) toInstall = 0; } } return(toInstall); } /* * autoupgradefindConflicts: * @name: name of the resource * @version: the version * @release: the release * * Search in the upgrade list the package generating the conflict * * Returns the index in case of success -1 in case of failure */ int autoupgradefindConflicts(const char *name, const char *version, const char *release) { int i; for (i = 0;i < autoupgradeLen;i++) { if (!strcmp(name, autoupgradeName[i])) { if (version == NULL) return(i); if (!strcmp(version, autoupgradeVersion[i])) { if (release == NULL) return(i); if (!strcmp(release, autoupgradeRelease[i])) return(i); } } } return(-1); } /* * autoupgradeSolveConflicts2: * @level: counter to avoid too deep recursions * @islast: indicate taht it's the last batch * * Display and try to solve possible problems * * Returns 0 in case of success or -1 in case of failure */ int autoupgradeSolveConflicts(int level, int islast) { struct rpmDependencyConflict *conflicts; int flags, i, nbPackages = 0, res; int numConflicts; int noInstall = 0; int culprit; rpmTransactionSet autoupgradeTransaction = NULL; if (rpmfindVerbose > 1) printf("autoupgradeSolveConflicts(level %d, islast %d)\n", level, islast); if (level > MAX_SOLVE_RECURSION_DEP) { return(-1); } if ((!islast) && (autoupgradeNbConflicts > MAX_BATCH_CONFLICTS)) { rpmdepFreeConflicts(conflicts, numConflicts); return(-1); } /* * Build the transaction list */ autoupgradeTransaction = rpmtransCreateSet(myDb, "/"); if (autoupgradeTransaction == NULL) { printf("rpmfind: failed to build the transaction set\n"); return(-1); } for (i = 0;i < autoupgradeLen;i++) { if (autoupgradeDrop[i]) continue; if ((!islast) && (autoupgradeConflict[i])) continue; rpmtransAddPackage(autoupgradeTransaction, autoupgradeHeaders[i], NULL, autoupgradeFiles[i], INSTALL_UPGRADE, NULL); nbPackages++; } if (nbPackages == 0) { if (rpmfindVerbose > 1) printf("List left is empty.\n"); rpmtransFree(autoupgradeTransaction); return(0); } /* * Check for possible conflicts */ if (rpmdepCheck(autoupgradeTransaction, &conflicts, &numConflicts)) { printf("rpmfind: Dependency check failed.\n"); noInstall = 1; } else if (conflicts == NULL) { if (rpmfindVerbose > 1) printf("rpmfind: Dependency passed.\n"); } rpmtransFree(autoupgradeTransaction); if (noInstall) return(1); if (conflicts == NULL) return(0); /* * Bad news remove every package with missing dependancies. */ if (islast) printf("Conflict found: \n"); for (i = 0; i < numConflicts; i++) { flags = conflicts[i].needsFlags; if (!islast) { autoupgradeNbConflicts++; if (autoupgradeNbConflicts > MAX_BATCH_CONFLICTS) { printf("Too many conflicts .. postponing\n"); rpmdepFreeConflicts(conflicts, numConflicts); return(1); } } /* * Output remaining conflicts only in the last batch */ if (islast) { if (conflicts[i].sense == RPMDEP_SENSE_REQUIRES) { printf(" %s-%s-%s requires %s", conflicts[i].byName, conflicts[i].byVersion, conflicts[i].byRelease, conflicts[i].needsName); } else { printf(" %s-%s-%s conflicts with %s", conflicts[i].byName, conflicts[i].byVersion, conflicts[i].byRelease, conflicts[i].needsName); } if (flags) { printf(" "); if (flags & RPMSENSE_LESS) printf("<"); if (flags & RPMSENSE_GREATER) printf(">"); if (flags & RPMSENSE_EQUAL) printf("="); if (flags & RPMSENSE_SERIAL) printf("S"); printf(" "); printf(conflicts[i].needsVersion); } printf("\n"); } /* * If there is a conflict or if the package generating the * unresolved requires is not in the list of upgrades, * there isn't much we can do except postpone the package * upgrade */ culprit = autoupgradefindConflicts(conflicts[i].byName, conflicts[i].byVersion, conflicts[i].byRelease); if (culprit >= 0) { if (islast) printf(" Error generated by %s\n", autoupgradeFiles[culprit]); if (conflicts[i].sense == RPMDEP_SENSE_REQUIRES) { if ((islast) && (strcmp(autoupgradeName[culprit], conflicts[i].needsName))) { /* * The new package requires another one * We should try to do a closure either by scanning * history about this dependancy or doing a net lookup * TODO !!!! */ if (autoupgradeLookupDep(conflicts[i].needsName, flags, conflicts[i].needsVersion, NULL) > 0) { res = autoupgradeSolveConflicts(level + 1, islast); if (res == 0) { rpmdepFreeConflicts(conflicts, numConflicts); return(0); } if ((!islast) && (autoupgradeNbConflicts > MAX_BATCH_CONFLICTS)) { rpmdepFreeConflicts(conflicts, numConflicts); return(1); } } } else if (islast) { /* * an installed program asks for an old dependancy */ } if ((islast) && (rpmfindVerbose)) printf("trying to drop it from list\n"); autoupgradeDrop[culprit] = 1; autoupgradeConflict[culprit] = 1; res = autoupgradeSolveConflicts(level + 1, islast); if (res == 0) { rpmdepFreeConflicts(conflicts, numConflicts); return(0); } if ((!islast) && (autoupgradeNbConflicts > MAX_BATCH_CONFLICTS)) { rpmdepFreeConflicts(conflicts, numConflicts); return(1); } } else { if ((islast) && (rpmfindVerbose)) printf("trying to drop it from list\n"); autoupgradeDrop[culprit] = 1; autoupgradeConflict[culprit] = 1; res = autoupgradeSolveConflicts(level + 1, islast); if (res == 0) { rpmdepFreeConflicts(conflicts, numConflicts); return(0); } if ((!islast) && (autoupgradeNbConflicts > MAX_BATCH_CONFLICTS)) { rpmdepFreeConflicts(conflicts, numConflicts); return(1); } } } else { /* * This is one of the installed packages which would * break due to the update, one of the replaced packages * provides a ressource that is required by an installed * and non-upgraded packages. */ Header ih = NULL; int found = 0; const char *iname = NULL; const char *iversion = NULL; const char *irelease = NULL; #ifdef USE_RPMIO { rpmdbMatchIterator mi; Header myih; mi = rpmdbInitIterator(myDb, RPMTAG_PROVIDENAME, conflicts[i].needsName, 0); if (islast) printf(" Resource %s is provided by:", conflicts[i].needsName); while ((myih = rpmdbNextIterator(mi)) != NULL) { /* XXX preserve the last header's memory references in ih */ if (ih) headerFree(ih); ih = headerLink(myih); headerNVR(ih, &iname, &iversion, &irelease); if (islast) printf(" %s-%s-%s\n", iname, iversion, irelease); found = 1; break; } rpmdbFreeIterator(mi); } #else /* USE_RPMIO */ { dbiIndexSet matches; int_32 count, type; if (rpmdbFindByProvides(myDb, conflicts[i].needsName, &matches) == 0) { int j; if (islast) printf(" Resource %s is provided by:", conflicts[i].needsName); for (j = 0; j < matches.count; j++) { if (matches.recs[j].recOffset) { ih = rpmdbGetRecord(myDb, matches.recs[j].recOffset); if (!ih) { printf("error: could not read database record\n"); } else { headerGetEntry(ih, RPMTAG_NAME, &type, (void **) &iname, &count); headerGetEntry(ih, RPMTAG_VERSION, &type, (void **) &iversion, &count); headerGetEntry(ih, RPMTAG_RELEASE, &type, (void **) &irelease, &count); if (islast) printf(" %s-%s-%s\n", iname, iversion, irelease); found = 1; break; } } } dbiFreeIndexRecord(matches); } } #endif /* USE_RPMIO */ if (ih == NULL) /* Keep looking? */ #ifdef USE_RPMIO { rpmdbMatchIterator mi; Header myih; mi = rpmdbInitIterator(myDb, RPMDBI_LABEL, conflicts[i].needsName, 0); if (mi == NULL) { if (islast) printf(" Resource %s not installed\n", conflicts[i].needsName); } else { if (islast) printf(" Package %s is installed as:", conflicts[i].needsName); while ((myih = rpmdbNextIterator(mi)) != NULL) { /* XXX preserve the last header's memory references in ih */ if (ih) headerFree(ih); ih = headerLink(myih); headerNVR(ih, &iname, &iversion, &irelease); if (islast) printf(" %s-%s-%s ", iname, iversion, irelease); found = 1; } if (islast) printf("\n"); } rpmdbFreeIterator(mi); } #else /* USE_RPMIO */ { dbiIndexSet matches; int_32 count, type; res = rpmdbFindByLabel(myDb, conflicts[i].needsName,&matches); if (res == 1) { if (islast) printf(" Resource %s not installed\n", conflicts[i].needsName); } else if (res == 2) { printf("Error looking for package %s\n", conflicts[i].needsName); } else { int j; if (islast) printf(" Package %s is installed as:", conflicts[i].needsName); for (j = 0; j < matches.count; j++) { if (matches.recs[j].recOffset) { ih = rpmdbGetRecord(myDb, matches.recs[j].recOffset); if (!ih) { printf( "error: could not read database record\n"); } else { /* extract informations from the header */ headerGetEntry(ih, RPMTAG_NAME, &type, (void **) &iname, &count); headerGetEntry(ih, RPMTAG_VERSION, &type, (void **) &iversion, &count); headerGetEntry(ih, RPMTAG_RELEASE, &type, (void **) &irelease, &count); if (islast) printf(" %s-%s-%s ", iname, iversion, irelease); found = 1; } } } if (islast) printf("\n"); dbiFreeIndexRecord(matches); } } #endif /* USE_RPMIO */ if (found) { culprit = autoupgradefindConflicts(iname, NULL, NULL); if (culprit >= 0) { if (islast) { printf(" Error generated by %s\n", autoupgradeFiles[culprit]); printf(" trying to drop it from list\n"); } autoupgradeDrop[culprit] = 1; autoupgradeConflict[culprit] = 1; } else { if (islast) printf( "Could not found the update overriding %s-%s-%s\n", iname, iversion, irelease); } headerFree(ih); if (culprit < 0) return(1); } else { if (islast) printf("Could not found the package providing %s\n", conflicts[i].needsName); rpmdepFreeConflicts(conflicts, numConflicts); return(1); } if ((i % 10) == 0) autoupgradeSaveHistory(); } autoupgradeSaveHistory(); } /* * Cleanup */ if (conflicts) rpmdepFreeConflicts(conflicts, numConflicts); return(1); } /* * autoupgradeInstall: * @noInstall: flag to disable installation * * Run (or print) the autoupgrade command * * Returns the result of the command */ int autoupgradeInstall(int noInstall, int islast) { char *args[MAX_SIMULTANEOUS_UPGRADE + 3]; int nbFiles = 0; int i, j; int status = 0; /* * Print or launch the rpm command, depending on conflicts found * and whether we got root priviledges */ args[0] = "rpm"; args[1] = "-U"; for (i = 0, j = 2,nbFiles = 0;i < autoupgradeLen;i++) { if (autoupgradeDrop[i]) continue; if ((!islast) && (autoupgradeConflict[i])) continue; args[j++] = autoupgradeFiles[i]; nbFiles++; } args[j++] = NULL; if (nbFiles > 0) { if ((noInstall == 0) && ((getuid() == 0) || (geteuid() == 0))) { int pid; int i; /* * Release the RPM database lock */ terminateRpmLookup(); pid = fork(); if (pid == -1) { fprintf(stderr, "Couldn't fork: %s\n", strerror(errno)); } if (pid) { printf("executing: rpm -U "); for (i = 0; i < nbFiles; i++) printf("%s ", args[i + 2]); printf("\n"); wait(&status); printf("Done: status code %d\n", status); } else { if (execvp("rpm", args) == -1) { fprintf(stderr, "Couldn't exec: %s\n", strerror(errno)); exit(1); } } if ((status == 0) && (!rpmfindNoDelete)) { /* All went well -- remove files */ int i; for (i = 0; i < nbFiles; i++) { struct stat statbuf; if (!stat(args[i + 2], &statbuf)) { if (unlink(args[i + 2])) { fprintf(stderr, "Failed to unlink %s: %s\n", args[i + 2], strerror(errno)); } } } } else if (status != 0) { fprintf(stderr, "Error installing: rpm returned %d\n", status); fprintf(stderr, "Please fix this and restart rpmfind\n"); exit(status); } /* * take the RPM database lock */ startRpmLookup(); } else { int i; printf("Need to run : rpm -U "); for (i = 0; i < nbFiles; i++) printf("%s ", args[i + 2]); printf("\n"); } } return(status); } /* * autoupgradeRunBatch: * @islast: indicate the last batch of upgrades * * Sort out the installable packages of a batch, then run the batch * * Returns the result of the command */ int autoupgradeRunBatch(int islast) { int noInstall; int i, j; /* * Try to solve the list of possible conflicts */ autoupgradeNbConflicts = 0; noInstall = autoupgradeSolveConflicts(0, islast); if (!noInstall) { /* * do the installation/print */ noInstall = autoupgradeInstall(noInstall, islast); /* * Cleanup the packages which (would) have been installed */ if (!noInstall) { for (i = 0, j = 0;i < autoupgradeLen ;i++) { if (autoupgradeDrop[i]) { autoupgradeName[j] = autoupgradeName[i]; autoupgradeVersion[j] = autoupgradeVersion[i]; autoupgradeRelease[j] = autoupgradeRelease[i]; autoupgradeHeaders[j] = autoupgradeHeaders[i]; autoupgradeFiles[j] = autoupgradeFiles[i]; autoupgradeDrop[j] = 0; j++; } else { free(autoupgradeName[i]); free(autoupgradeVersion[i]); free(autoupgradeRelease[i]); headerFree(autoupgradeHeaders[i]); free(autoupgradeFiles[i]); autoupgradeName[i] = NULL; autoupgradeVersion[i] = NULL; autoupgradeRelease[i] = NULL; autoupgradeHeaders[i] = NULL; autoupgradeFiles[i] = NULL; autoupgradeDrop[i] = 0; } } autoupgradeLen = j; } } autoupgradeSaveHistory(); return(noInstall); } /* * autoupgradeRun: * * Run an autoupgrade check. The autoupgrade process consists of the * following steps: * 1/ Get the location for the upgrades * 2/ Build a directory list * 3/ Check for preinstalled packages on that list * 4/ Download the packages not installed * 5/ check the signature on those packages * 6/ Check for possible conflicts on the upgrade * 7/ Possibly load additionnal packages for completing the upgrade * 8/ check the signature of those packages too * 9/ Drop packages which would cause an unresolvable conflict * 10/ print or run the rpm command to update * * This can certaily be improved ! * * Returns 0 or 1 depending on availbility of packages to upgrade, -1 for * unrecoverable errors */ int autoupgradeRun(void) { int i, j, k, res; char *autoupgradeURL; char **filelist; char autom = rpmfindAutomatic; int noInstall = 0; int nbInstall = 0; guessRpmDistribution(); if (rpmfindVerbose) printf("autoupgradeRun\n"); umask(0077); autoupgradeLoadHistory(); rpmfindCheckSigContext(); if (autoupgradeURLListLen == 0) { /* * Depending on the system try to guess the origin for autoupgrades * TODO !!!! */ printf("autoupgrade: guess of upgrade URL not coded\n"); printf("Add autoupgradeURL entries to your .rpmfind\n"); } rpmfindAutomatic = 1; /* * Create the list of packages to upgrade */ for (j = 0;j < autoupgradeURLListLen;j++) { int nbfiles; autoupgradeURL = autoupgradeURLList[j]; if (autoupgradeURL == NULL) break; filelist = autoupgradeBuildDirList(autoupgradeURL); if (filelist == NULL) continue; /* * Stupid trick but latest package are more likely to appear * last in the directory listing... */ for (i = 0;filelist[i] != NULL;i++); nbfiles = i; /* * Try to load first critical packages */ for (i = 0, k = nbfiles;i < nbfiles; i++) { if (autoupgradeShouldAttemptFirst(filelist[i])) { filelist[k++] = strdup(filelist[i]); } } nbfiles = k; for (i = (nbfiles - 1);i >= 0;i--) { if (autoupgradeShouldForce(filelist[i])) { res = autoupgradeToInstall(autoupgradeURL, filelist[i], 1); } else { res = autoupgradeToInstall(autoupgradeURL, filelist[i], 0); } if (res == 1) nbInstall++; if (nbInstall >= MAX_PACKAGES_BATCHES) { autoupgradeRunBatch(0); nbInstall = 0; } } } rpmfindAutomatic = autom; /* * do the installation/print */ res = autoupgradeRunBatch(1); /* * Release the RPM database lock */ terminateRpmLookup(); autoupgradeSaveHistory(); /* * Cleanup. */ /* * Debug */ return(!noInstall); }