diff --git a/lib/transaction.c b/lib/transaction.c index bee30a172..92cfbd1f7 100644 --- a/lib/transaction.c +++ b/lib/transaction.c @@ -65,37 +65,7 @@ struct diskspaceInfo { probably right :-( */ #define BLOCK_ROUND(size, block) (((size) + (block) - 1) / (block)) -static rpmProblemSet psCreate(void); -static void psAppend(rpmProblemSet probs, rpmProblemType type, - const void * key, Header h, const char * str1, - Header altHeader, unsigned long ulong1); -static int archOkay(Header h); -static int osOkay(Header h); -static Header relocateFileList(struct availablePackage * alp, - rpmProblemSet probs, Header h, - enum fileActions * actions, - int allowBadRelocate); -static int psTrim(rpmProblemSet filter, rpmProblemSet target); -static int sharedCmp(const void * one, const void * two); -static enum fileActions decideFileFate(const char * filespec, short dbMode, - char * dbMd5, char * dbLink, short newMode, - char * newMd5, char * newLink, int newFlags, - int brokenMd5); -enum fileTypes whatis(short mode); -static int filecmp(short mode1, char * md51, char * link1, - short mode2, char * md52, char * link2); -static int handleInstInstalledFiles(struct fileInfo * fi, rpmdb db, - struct sharedFileInfo * shared, - int sharedCount, int reportConflicts, - rpmProblemSet probs); -static int handleRmvdInstalledFiles(struct fileInfo * fi, rpmdb db, - struct sharedFileInfo * shared, - int sharedCount); -void handleOverlappedFiles(struct fileInfo * fi, hashTable ht, - rpmProblemSet probs, struct diskspaceInfo * dsl); -static int ensureOlder(rpmdb db, Header new, int dbOffset, rpmProblemSet probs, - const void * key); -static void skipFiles(struct fileInfo * fi, int noDocs); +#define XSTRCMP(a, b) ((!(a) && !(b)) || ((a) && (b) && !strcmp((a), (b)))) static void freeFi(struct fileInfo *fi) { @@ -147,15 +117,783 @@ static void freeFl(rpmTransactionSet ts, struct fileInfo *flList) } } -#define XSTRCMP(a, b) ((!(a) && !(b)) || ((a) && (b) && !strcmp((a), (b)))) +void rpmtransSetScriptFd(rpmTransactionSet ts, FD_t fd) +{ + ts->scriptFd = fd; +} + +static rpmProblemSet psCreate(void) +{ + rpmProblemSet probs; + + probs = malloc(sizeof(*probs)); + probs->numProblems = probs->numProblemsAlloced = 0; + probs->probs = NULL; + + return probs; +} + +static void psAppend(rpmProblemSet probs, rpmProblemType type, + const void * key, Header h, const char * str1, + Header altH, unsigned long ulong1) +{ + if (probs->numProblems == probs->numProblemsAlloced) { + if (probs->numProblemsAlloced) + probs->numProblemsAlloced *= 2; + else + probs->numProblemsAlloced = 2; + probs->probs = realloc(probs->probs, + probs->numProblemsAlloced * sizeof(*probs->probs)); + } + + probs->probs[probs->numProblems].type = type; + probs->probs[probs->numProblems].key = key; + probs->probs[probs->numProblems].h = headerLink(h); + probs->probs[probs->numProblems].ulong1 = ulong1; + if (str1) + probs->probs[probs->numProblems].str1 = strdup(str1); + else + probs->probs[probs->numProblems].str1 = NULL; + + if (altH) + probs->probs[probs->numProblems].altH = headerLink(altH); + else + probs->probs[probs->numProblems].altH = NULL; + + probs->probs[probs->numProblems++].ignoreProblem = 0; +} + +static int archOkay(Header h) +{ + int_8 * pkgArchNum; + void * pkgArch; + int type, count, archNum; + + /* make sure we're trying to install this on the proper architecture */ + headerGetEntry(h, RPMTAG_ARCH, &type, (void **) &pkgArch, &count); + if (type == RPM_INT8_TYPE) { + /* old arch handling */ + rpmGetArchInfo(NULL, &archNum); + pkgArchNum = pkgArch; + if (archNum != *pkgArchNum) { + return 0; + } + } else { + /* new arch handling */ + if (!rpmMachineScore(RPM_MACHTABLE_INSTARCH, pkgArch)) { + return 0; + } + } + + return 1; +} + +static int osOkay(Header h) +{ + void * pkgOs; + int type, count; + + /* make sure we're trying to install this on the proper os */ + headerGetEntry(h, RPMTAG_OS, &type, (void **) &pkgOs, &count); + if (type == RPM_INT8_TYPE) { + /* v1 packages and v2 packages both used improper OS numbers, so just + deal with it hope things work */ + return 1; + } else { + /* new os handling */ + if (!rpmMachineScore(RPM_MACHTABLE_INSTOS, pkgOs)) { + return 0; + } + } + + return 1; +} + +void rpmProblemSetFree(rpmProblemSet probs) +{ + int i; + + for (i = 0; i < probs->numProblems; i++) { + headerFree(probs->probs[i].h); + if (probs->probs[i].str1) free(probs->probs[i].str1); + if (probs->probs[i].altH) headerFree(probs->probs[i].altH); + } + free(probs); +} + +static Header relocateFileList(struct availablePackage * alp, + rpmProblemSet probs, Header origH, + enum fileActions * actions, + int allowBadRelocate) +{ + int numValid, numRelocations; + int i, j, madeSwap, rc; + rpmRelocation * nextReloc, * relocations = NULL; + rpmRelocation * rawRelocations = alp->relocs; + rpmRelocation tmpReloc; + char ** validRelocations, ** actualRelocations; + char ** names; + char ** origNames; + int len = 0; + char * newName; + int_32 fileCount; + Header h; + int relocated = 0; + + if (!headerGetEntry(origH, RPMTAG_PREFIXES, NULL, + (void **) &validRelocations, &numValid)) + numValid = 0; + + if (!rawRelocations && !numValid) return headerLink(origH); + + h = headerCopy(origH); + + if (rawRelocations) { + for (i = 0; rawRelocations[i].newPath || rawRelocations[i].oldPath; + i++) ; + numRelocations = i; + } else { + numRelocations = 0; + } + relocations = alloca(sizeof(*relocations) * numRelocations); + + for (i = 0; i < numRelocations; i++) { + /* FIXME: default relocations (oldPath == NULL) need to be handled + in the UI, not rpmlib */ + + relocations[i].oldPath = + alloca(strlen(rawRelocations[i].oldPath) + 1); + strcpy(relocations[i].oldPath, rawRelocations[i].oldPath); + stripTrailingSlashes(relocations[i].oldPath); + + if (rawRelocations[i].newPath) { + relocations[i].newPath = + alloca(strlen(rawRelocations[i].newPath) + 1); + strcpy(relocations[i].newPath, rawRelocations[i].newPath); + stripTrailingSlashes(relocations[i].newPath); + } else { + relocations[i].newPath = NULL; + } + + if (relocations[i].newPath) { + for (j = 0; j < numValid; j++) + if (!strcmp(validRelocations[j], + relocations[i].oldPath)) break; + if (j == numValid && !allowBadRelocate) + psAppend(probs, RPMPROB_BADRELOCATE, alp->key, alp->h, + relocations[i].oldPath, NULL,0 ); + } + } + + /* stupid bubble sort, but it's probably faster here */ + for (i = 0; i < numRelocations; i++) { + madeSwap = 0; + for (j = 1; j < numRelocations; j++) { + if (strcmp(relocations[j - 1].oldPath, + relocations[j].oldPath) > 0) { + tmpReloc = relocations[j - 1]; + relocations[j - 1] = relocations[j]; + relocations[j] = tmpReloc; + madeSwap = 1; + } + } + if (!madeSwap) break; + } + + if (numValid) { + actualRelocations = malloc(sizeof(*actualRelocations) * numValid); + for (i = 0; i < numValid; i++) { + for (j = 0; j < numRelocations; j++) { + if (!strcmp(validRelocations[i], relocations[j].oldPath)) { + actualRelocations[i] = relocations[j].newPath; + break; + } + } + + if (j == numRelocations) + actualRelocations[i] = validRelocations[i]; + } + + headerAddEntry(h, RPMTAG_INSTPREFIXES, RPM_STRING_ARRAY_TYPE, + (void **) actualRelocations, numValid); + + free(actualRelocations); + free(validRelocations); + } + + headerGetEntry(h, RPMTAG_FILENAMES, NULL, (void **) &names, + &fileCount); + + /* go through things backwards so that /usr/local relocations take + precedence over /usr ones */ + for (i = fileCount - 1; i >= 0; i--) { + for (j = numRelocations - 1; j >= 0; j--) { + nextReloc = relocations + j; + len = strlen(relocations[j].oldPath); + rc = (!strncmp(relocations[j].oldPath, names[i], len) && + ((names[i][len] == '/') || !names[i][len])); + if (rc) break; + } + + if (j >= 0) { + nextReloc = relocations + j; + if (nextReloc->newPath) { + newName = alloca(strlen(nextReloc->newPath) + + strlen(names[i]) + 1); + strcpy(newName, nextReloc->newPath); + strcat(newName, names[i] + len); + rpmMessage(RPMMESS_DEBUG, _("relocating %s to %s\n"), + names[i], newName); + names[i] = newName; + relocated = 1; + } else if (actions) { + actions[i] = FA_SKIPNSTATE; + rpmMessage(RPMMESS_DEBUG, _("excluding %s\n"), names[i]); + } + } + } + + if (relocated) { + headerGetEntry(h, RPMTAG_FILENAMES, NULL, (void **) &origNames, NULL); + headerAddEntry(h, RPMTAG_ORIGFILENAMES, RPM_STRING_ARRAY_TYPE, + origNames, fileCount); + free(origNames); + headerModifyEntry(h, RPMTAG_FILENAMES, RPM_STRING_ARRAY_TYPE, + names, fileCount); + } + + free(names); + + return h; +} + +static int psTrim(rpmProblemSet filter, rpmProblemSet target) +{ + /* As the problem sets are generated in an order solely dependent + on the ordering of the packages in the transaction, and that + ordering can't be changed, the problem sets must be parallel to + on another. Additionally, the filter set must be a subset of the + target set, given the operations available on transaction set. + This is good, as it lets us perform this trim in linear time, rather + then logarithmic or quadratic. */ + rpmProblem * f, * t; + int gotProblems = 0; + + f = filter->probs; + t = target->probs; + + while ((f - filter->probs) < filter->numProblems) { + if (!f->ignoreProblem) { + f++; + continue; + } + while ((t - target->probs) < target->numProblems) { + if (f->h == t->h && f->type == t->type && t->key == f->key && + XSTRCMP(f->str1, t->str1)) + break; + t++; + gotProblems = 1; + } + + if ((t - target->probs) == target->numProblems) { + /* this can't happen ;-) lets be sane if it doesn though */ + break; + } + + t->ignoreProblem = f->ignoreProblem; + t++, f++; + } + + if ((t - target->probs) < target->numProblems) + gotProblems = 1; + + return gotProblems; +} + +static int sharedCmp(const void * one, const void * two) +{ + const struct sharedFileInfo * a = one; + const struct sharedFileInfo * b = two; + + if (a->otherPkg < b->otherPkg) + return -1; + else if (a->otherPkg > b->otherPkg) + return 1; + + return 0; +} + +static enum fileTypes whatis(short mode) +{ + enum fileTypes result; + + if (S_ISDIR(mode)) + result = XDIR; + else if (S_ISCHR(mode)) + result = CDEV; + else if (S_ISBLK(mode)) + result = BDEV; + else if (S_ISLNK(mode)) + result = LINK; + else if (S_ISSOCK(mode)) + result = SOCK; + else if (S_ISFIFO(mode)) + result = PIPE; + else + result = REG; + + return result; +} + +static enum fileActions decideFileFate(const char * filespec, short dbMode, + char * dbMd5, char * dbLink, short newMode, + char * newMd5, char * newLink, int newFlags, + int brokenMd5) +{ + char buffer[1024]; + char * dbAttr, * newAttr; + enum fileTypes dbWhat, newWhat, diskWhat; + struct stat sb; + int i, rc; + int save = (newFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SAVE; + + if (lstat(filespec, &sb)) { + /* the file doesn't exist on the disk create it unless the new + package has marked it as missingok */ + if (newFlags & RPMFILE_MISSINGOK) { + rpmMessage(RPMMESS_DEBUG, _("%s skipped due to missingok flag\n"), + filespec); + return FA_SKIP; + } else + return FA_CREATE; + } + + diskWhat = whatis(sb.st_mode); + dbWhat = whatis(dbMode); + newWhat = whatis(newMode); + + /* RPM >= 2.3.10 shouldn't create config directories -- we'll ignore + them in older packages as well */ + if (newWhat == XDIR) + return FA_CREATE; + + if (diskWhat != newWhat) { + return save; + } else if (newWhat != dbWhat && diskWhat != dbWhat) { + return save; + } else if (dbWhat != newWhat) { + return FA_CREATE; + } else if (dbWhat != LINK && dbWhat != REG) { + return FA_CREATE; + } + + if (dbWhat == REG) { + if (brokenMd5) + rc = mdfileBroken(filespec, buffer); + else + rc = mdfile(filespec, buffer); + + if (rc) { + /* assume the file has been removed, don't freak */ + return FA_CREATE; + } + dbAttr = dbMd5; + newAttr = newMd5; + } else /* dbWhat == LINK */ { + memset(buffer, 0, sizeof(buffer)); + i = readlink(filespec, buffer, sizeof(buffer) - 1); + if (i == -1) { + /* assume the file has been removed, don't freak */ + return FA_CREATE; + } + dbAttr = dbLink; + newAttr = newLink; + } + + /* this order matters - we'd prefer to CREATE the file if at all + possible in case something else (like the timestamp) has changed */ + + if (!strcmp(dbAttr, buffer)) { + /* this config file has never been modified, so + just replace it */ + return FA_CREATE; + } + + if (!strcmp(dbAttr, newAttr)) { + /* this file is the same in all versions of this package */ + return FA_SKIP; + } + + /* the config file on the disk has been modified, but + the ones in the two packages are different. It would + be nice if RPM was smart enough to at least try and + merge the difference ala CVS, but... */ + + return save; +} + +static int filecmp(short mode1, char * md51, char * link1, + short mode2, char * md52, char * link2) +{ + enum fileTypes what1, what2; + + what1 = whatis(mode1); + what2 = whatis(mode2); + + if (what1 != what2) return 1; + + if (what1 == LINK) + return strcmp(link1, link2); + else if (what1 == REG) + return strcmp(md51, md52); + + return 0; +} + +static int handleInstInstalledFiles(struct fileInfo * fi, rpmdb db, + struct sharedFileInfo * shared, + int sharedCount, int reportConflicts, + rpmProblemSet probs) +{ + Header h; + int i; + char ** otherMd5s, ** otherLinks; + char * otherStates; + uint_32 * otherFlags, * otherSizes; + uint_16 * otherModes; + int otherFileNum; + int fileNum; + int numReplaced = 0; + + if (!(h = rpmdbGetRecord(db, shared->otherPkg))) + return 1; + + headerGetEntryMinMemory(h, RPMTAG_FILEMD5S, NULL, + (void **) &otherMd5s, NULL); + headerGetEntryMinMemory(h, RPMTAG_FILELINKTOS, NULL, + (void **) &otherLinks, NULL); + headerGetEntryMinMemory(h, RPMTAG_FILESTATES, NULL, + (void **) &otherStates, NULL); + headerGetEntryMinMemory(h, RPMTAG_FILEMODES, NULL, + (void **) &otherModes, NULL); + headerGetEntryMinMemory(h, RPMTAG_FILEFLAGS, NULL, + (void **) &otherFlags, NULL); + headerGetEntryMinMemory(h, RPMTAG_FILESIZES, NULL, + (void **) &otherSizes, NULL); + + fi->replaced = malloc(sizeof(*fi->replaced) * sharedCount); + + for (i = 0; i < sharedCount; i++, shared++) { + otherFileNum = shared->otherFileNum; + fileNum = shared->pkgFileNum; + if (otherStates[otherFileNum] == RPMFILE_STATE_NORMAL) { + if (filecmp(otherModes[otherFileNum], + otherMd5s[otherFileNum], + otherLinks[otherFileNum], + fi->fmodes[fileNum], + fi->fmd5s[fileNum], + fi->flinks[fileNum])) { + if (reportConflicts) + psAppend(probs, RPMPROB_FILE_CONFLICT, fi->ap->key, + fi->ap->h, fi->fl[fileNum], h,0 ); + if (!(otherFlags[otherFileNum] | fi->fflags[fileNum]) + & RPMFILE_CONFIG) { + if (!shared->isRemoved) + fi->replaced[numReplaced++] = *shared; + } + } + + if ((otherFlags[otherFileNum] | fi->fflags[fileNum]) + & RPMFILE_CONFIG) { + fi->actions[fileNum] = decideFileFate(fi->fl[fileNum], + otherModes[otherFileNum], + otherMd5s[otherFileNum], + otherLinks[otherFileNum], + fi->fmodes[fileNum], + fi->fmd5s[fileNum], + fi->flinks[fileNum], + fi->fflags[fileNum], + !headerIsEntry(h, RPMTAG_RPMVERSION)); + } + + fi->replacedSizes[fileNum] = otherSizes[otherFileNum]; + } + } + + free(otherMd5s); + free(otherLinks); + headerFree(h); + + fi->replaced = realloc(fi->replaced, + sizeof(*fi->replaced) * (numReplaced + 1)); + fi->replaced[numReplaced].otherPkg = 0; + + return 0; +} + +static int handleRmvdInstalledFiles(struct fileInfo * fi, rpmdb db, + struct sharedFileInfo * shared, + int sharedCount) +{ + Header h; + int otherFileNum; + int fileNum; + char * otherStates; + int i; + + if (!(h = rpmdbGetRecord(db, shared->otherPkg))) + return 1; + + headerGetEntryMinMemory(h, RPMTAG_FILESTATES, NULL, + (void **) &otherStates, NULL); + + for (i = 0; i < sharedCount; i++, shared++) { + otherFileNum = shared->otherFileNum; + fileNum = shared->pkgFileNum; + + if (otherStates[otherFileNum] == RPMFILE_STATE_NORMAL) + fi->actions[fileNum] = FA_SKIP; + } + + headerFree(h); + + return 0; +} + +static void handleOverlappedFiles(struct fileInfo * fi, hashTable ht, + rpmProblemSet probs, struct diskspaceInfo * dsl) +{ + int i, j; + struct fileInfo ** recs; + int numRecs; + int otherPkgNum, otherFileNum; + struct stat sb; + char mdsum[50]; + int rc; + struct diskspaceInfo * ds = NULL; + uint_32 fixupSize = 0; + + for (i = 0; i < fi->fc; i++) { + if (fi->actions[i] == FA_SKIP || fi->actions[i] == FA_SKIPNSTATE) + continue; + + if (dsl) { + ds = dsl; + while (ds->block && ds->dev != fi->fps[i].dev) ds++; + if (!ds->block) ds = NULL; + fixupSize = 0; + } + + htGetEntry(ht, &fi->fps[i], (void ***) &recs, &numRecs, NULL); + + /* We need to figure out the current fate of this file. So, + work backwards from this file and look for a final action + we can work against. */ + for (j = 0; recs[j] != fi; j++); + + otherPkgNum = j - 1; + otherFileNum = -1; /* keep gcc quiet */ + while (otherPkgNum >= 0) { + if (recs[otherPkgNum]->type == TR_ADDED) { + /* TESTME: there are more efficient searches in the world... */ + for (otherFileNum = 0; otherFileNum < recs[otherPkgNum]->fc; + otherFileNum++) + if (FP_EQUAL(fi->fps[i], + recs[otherPkgNum]->fps[otherFileNum])) + break; + if ((otherFileNum >= 0) && + (recs[otherPkgNum]->actions[otherFileNum] != FA_UNKNOWN)) + break; + } + otherPkgNum--; + } + + if (fi->type == TR_ADDED && otherPkgNum < 0) { + if (fi->actions[i] == FA_UNKNOWN) { + if ((fi->fflags[i] & RPMFILE_CONFIG) && + !lstat(fi->fl[i], &sb)) { + fi->actions[i] = (fi->fflags[i] & RPMFILE_NOREPLACE) + ? FA_ALTNAME : FA_BACKUP; + } else { + fi->actions[i] = FA_CREATE; + } + } + } else if (fi->type == TR_ADDED) { + if (probs && filecmp(recs[otherPkgNum]->fmodes[otherFileNum], + recs[otherPkgNum]->fmd5s[otherFileNum], + recs[otherPkgNum]->flinks[otherFileNum], + fi->fmodes[i], + fi->fmd5s[i], + fi->flinks[i])) { + psAppend(probs, RPMPROB_NEW_FILE_CONFLICT, fi->ap->key, + fi->ap->h, fi->fl[i], recs[otherPkgNum]->ap->h, 0); + } + + fixupSize = recs[otherPkgNum]->fsizes[otherFileNum]; + + /* FIXME: is this right??? it locks us into the config + file handling choice we already made, which may very + well be exactly right. What about noreplace files?? */ + fi->actions[i] = FA_CREATE; + } else if (fi->type == TR_REMOVED && otherPkgNum >= 0) { + fi->actions[i] = FA_SKIP; + } else if (fi->type == TR_REMOVED) { + if (fi->actions[i] != FA_SKIP && fi->actions[i] != FA_SKIPNSTATE && + fi->fstates[i] == RPMFILE_STATE_NORMAL ) { + if (S_ISREG(fi->fmodes[i]) && + (fi->fflags[i] & RPMFILE_CONFIG)) { + rc = mdfile(fi->fl[i], mdsum); + if (!rc && strcmp(fi->fmd5s[i], mdsum)) { + fi->actions[i] = FA_BACKUP; + } else { + /* FIXME: config files may need to be saved */ + fi->actions[i] = FA_REMOVE; + } + } else { + fi->actions[i] = FA_REMOVE; + } + } + } + + if (ds) { + uint_32 s = BLOCK_ROUND(fi->fsizes[i], ds->block); + + switch (fi->actions[i]) { + case FA_BACKUP: + case FA_SAVE: + case FA_ALTNAME: + ds->needed += s; + break; + + /* FIXME: If a two packages share a file (same md5sum), and + that file is being replaced on disk, will ds->needed get + decremented twice? Quite probably! */ + case FA_CREATE: + ds->needed += s; + ds->needed -= BLOCK_ROUND(fi->replacedSizes[i], ds->block); + break; + + case FA_REMOVE: + ds->needed -= s; + break; + + default: + break; + } + + ds->needed -= BLOCK_ROUND(fixupSize, ds->block); + } + } +} + +static int ensureOlder(rpmdb db, Header new, int dbOffset, rpmProblemSet probs, + const void * key) +{ + Header old; + int result, rc = 0; + + old = rpmdbGetRecord(db, dbOffset); + if (old == NULL) return 1; + + result = rpmVersionCompare(old, new); + if (result <= 0) + rc = 0; + else if (result > 0) { + rc = 1; + psAppend(probs, RPMPROB_OLDPACKAGE, key, new, NULL, old, 0); + } + + headerFree(old); + + return rc; +} + +static void skipFiles(struct fileInfo * fi, int noDocs) +{ + int i, j; + char ** netsharedPaths = NULL, ** nsp; + char ** fileLangs, ** languages, ** lang; + char * oneLang[2] = { NULL, NULL }; + int freeLanguages = 0; + char * chptr; + + if (!noDocs) + noDocs = rpmExpandNumeric("%{_excludedocs}"); + + { const char *tmpPath = rpmExpand("%{_netsharedpath}", NULL); + if (tmpPath && *tmpPath != '%') + netsharedPaths = splitString(tmpPath, strlen(tmpPath), ':'); + xfree(tmpPath); + } + + if (!headerGetEntry(fi->h, RPMTAG_FILELANGS, NULL, (void **) &fileLangs, + NULL)) + fileLangs = NULL; + + if ((chptr = getenv("LINGUAS"))) { + languages = splitString(chptr, strlen(chptr), ':'); + freeLanguages = 1; + } else if ((oneLang[0] = getenv("LANG"))) { + languages = oneLang; + } else { + oneLang[0] = "en"; + languages = oneLang; + } + + for (i = 0; i < fi->fc; i++) { + if (fi->actions[i] == FA_SKIP || fi->actions[i] == FA_SKIPNSTATE) + continue; + + /* netsharedPaths are not relative to the current root (though + they do need to take package relocations into account) */ + for (nsp = netsharedPaths; nsp && *nsp; nsp++) { + j = strlen(*nsp); + if (!strncmp(fi->fl[i], *nsp, j) && + (fi->fl[i][j] == '\0' || + fi->fl[i][j] == '/')) + break; + } + + if (nsp && *nsp) { + fi->actions[i] = FA_SKIPNSTATE; + continue; + } + + if (fileLangs && languages && *fileLangs[i]) { + for (lang = languages; *lang; lang++) { + const char *l, *le; + for (l = fileLangs[i]; *l; l = le) { + for (le = l; *le && *le != '|'; le++) + ; + if ((le-l) > 0 && !strncmp(*lang, l, (le-l))) + goto lingo; + if (*le == '|') le++; /* skip over | */ + } + } + lingo: + if (!*lang) { + fi->actions[i] = FA_SKIPNSTATE; + continue; + } + } + + if (noDocs && (fi->fflags[i] & RPMFILE_DOC)) + fi->actions[i] = FA_SKIPNSTATE; + } + + if (netsharedPaths) freeSplitString(netsharedPaths); + if (fileLangs) free(fileLangs); + if (freeLanguages) freeSplitString(languages); +} #define NOTIFY(_x) if (notify) notify _x -/* Return -1 on error, > 0 if newProbs is set, 0 if everything - happened */ +/* Return -1 on error, > 0 if newProbs is set, 0 if everything happened */ + int rpmRunTransactions(rpmTransactionSet ts, rpmCallbackFunction notify, void * notifyData, rpmProblemSet okProbs, - rpmProblemSet * newProbs, int flags, int ignoreSet) { + rpmProblemSet * newProbs, int flags, int ignoreSet) +{ int i, j; int rc, ourrc = 0; struct availablePackage * alp; @@ -571,755 +1309,3 @@ int rpmRunTransactions(rpmTransactionSet ts, rpmCallbackFunction notify, else return 0; } - -void rpmtransSetScriptFd(rpmTransactionSet ts, FD_t fd) { - ts->scriptFd = fd; -} - -static rpmProblemSet psCreate(void) { - rpmProblemSet probs; - - probs = malloc(sizeof(*probs)); - probs->numProblems = probs->numProblemsAlloced = 0; - probs->probs = NULL; - - return probs; -} - -static void psAppend(rpmProblemSet probs, rpmProblemType type, - const void * key, Header h, const char * str1, - Header altH, unsigned long ulong1) { - if (probs->numProblems == probs->numProblemsAlloced) { - if (probs->numProblemsAlloced) - probs->numProblemsAlloced *= 2; - else - probs->numProblemsAlloced = 2; - probs->probs = realloc(probs->probs, - probs->numProblemsAlloced * sizeof(*probs->probs)); - } - - probs->probs[probs->numProblems].type = type; - probs->probs[probs->numProblems].key = key; - probs->probs[probs->numProblems].h = headerLink(h); - probs->probs[probs->numProblems].ulong1 = ulong1; - if (str1) - probs->probs[probs->numProblems].str1 = strdup(str1); - else - probs->probs[probs->numProblems].str1 = NULL; - - if (altH) - probs->probs[probs->numProblems].altH = headerLink(altH); - else - probs->probs[probs->numProblems].altH = NULL; - - probs->probs[probs->numProblems++].ignoreProblem = 0; -} - -static int archOkay(Header h) { - int_8 * pkgArchNum; - void * pkgArch; - int type, count, archNum; - - /* make sure we're trying to install this on the proper architecture */ - headerGetEntry(h, RPMTAG_ARCH, &type, (void **) &pkgArch, &count); - if (type == RPM_INT8_TYPE) { - /* old arch handling */ - rpmGetArchInfo(NULL, &archNum); - pkgArchNum = pkgArch; - if (archNum != *pkgArchNum) { - return 0; - } - } else { - /* new arch handling */ - if (!rpmMachineScore(RPM_MACHTABLE_INSTARCH, pkgArch)) { - return 0; - } - } - - return 1; -} - -static int osOkay(Header h) { - void * pkgOs; - int type, count; - - /* make sure we're trying to install this on the proper os */ - headerGetEntry(h, RPMTAG_OS, &type, (void **) &pkgOs, &count); - if (type == RPM_INT8_TYPE) { - /* v1 packages and v2 packages both used improper OS numbers, so just - deal with it hope things work */ - return 1; - } else { - /* new os handling */ - if (!rpmMachineScore(RPM_MACHTABLE_INSTOS, pkgOs)) { - return 0; - } - } - - return 1; -} - -void rpmProblemSetFree(rpmProblemSet probs) { - int i; - - for (i = 0; i < probs->numProblems; i++) { - headerFree(probs->probs[i].h); - if (probs->probs[i].str1) free(probs->probs[i].str1); - if (probs->probs[i].altH) headerFree(probs->probs[i].altH); - } - free(probs); -} - -static Header relocateFileList(struct availablePackage * alp, - rpmProblemSet probs, Header origH, - enum fileActions * actions, - int allowBadRelocate) { - int numValid, numRelocations; - int i, j, madeSwap, rc; - rpmRelocation * nextReloc, * relocations = NULL; - rpmRelocation * rawRelocations = alp->relocs; - rpmRelocation tmpReloc; - char ** validRelocations, ** actualRelocations; - char ** names; - char ** origNames; - int len = 0; - char * newName; - int_32 fileCount; - Header h; - int relocated = 0; - - if (!headerGetEntry(origH, RPMTAG_PREFIXES, NULL, - (void **) &validRelocations, &numValid)) - numValid = 0; - - if (!rawRelocations && !numValid) return headerLink(origH); - - h = headerCopy(origH); - - if (rawRelocations) { - for (i = 0; rawRelocations[i].newPath || rawRelocations[i].oldPath; - i++) ; - numRelocations = i; - } else { - numRelocations = 0; - } - relocations = alloca(sizeof(*relocations) * numRelocations); - - for (i = 0; i < numRelocations; i++) { - /* FIXME: default relocations (oldPath == NULL) need to be handled - in the UI, not rpmlib */ - - relocations[i].oldPath = - alloca(strlen(rawRelocations[i].oldPath) + 1); - strcpy(relocations[i].oldPath, rawRelocations[i].oldPath); - stripTrailingSlashes(relocations[i].oldPath); - - if (rawRelocations[i].newPath) { - relocations[i].newPath = - alloca(strlen(rawRelocations[i].newPath) + 1); - strcpy(relocations[i].newPath, rawRelocations[i].newPath); - stripTrailingSlashes(relocations[i].newPath); - } else { - relocations[i].newPath = NULL; - } - - if (relocations[i].newPath) { - for (j = 0; j < numValid; j++) - if (!strcmp(validRelocations[j], - relocations[i].oldPath)) break; - if (j == numValid && !allowBadRelocate) - psAppend(probs, RPMPROB_BADRELOCATE, alp->key, alp->h, - relocations[i].oldPath, NULL,0 ); - } - } - - /* stupid bubble sort, but it's probably faster here */ - for (i = 0; i < numRelocations; i++) { - madeSwap = 0; - for (j = 1; j < numRelocations; j++) { - if (strcmp(relocations[j - 1].oldPath, - relocations[j].oldPath) > 0) { - tmpReloc = relocations[j - 1]; - relocations[j - 1] = relocations[j]; - relocations[j] = tmpReloc; - madeSwap = 1; - } - } - if (!madeSwap) break; - } - - if (numValid) { - actualRelocations = malloc(sizeof(*actualRelocations) * numValid); - for (i = 0; i < numValid; i++) { - for (j = 0; j < numRelocations; j++) { - if (!strcmp(validRelocations[i], relocations[j].oldPath)) { - actualRelocations[i] = relocations[j].newPath; - break; - } - } - - if (j == numRelocations) - actualRelocations[i] = validRelocations[i]; - } - - headerAddEntry(h, RPMTAG_INSTPREFIXES, RPM_STRING_ARRAY_TYPE, - (void **) actualRelocations, numValid); - - free(actualRelocations); - free(validRelocations); - } - - headerGetEntry(h, RPMTAG_FILENAMES, NULL, (void **) &names, - &fileCount); - - /* go through things backwards so that /usr/local relocations take - precedence over /usr ones */ - for (i = fileCount - 1; i >= 0; i--) { - for (j = numRelocations - 1; j >= 0; j--) { - nextReloc = relocations + j; - len = strlen(relocations[j].oldPath); - rc = (!strncmp(relocations[j].oldPath, names[i], len) && - ((names[i][len] == '/') || !names[i][len])); - if (rc) break; - } - - if (j >= 0) { - nextReloc = relocations + j; - if (nextReloc->newPath) { - newName = alloca(strlen(nextReloc->newPath) + - strlen(names[i]) + 1); - strcpy(newName, nextReloc->newPath); - strcat(newName, names[i] + len); - rpmMessage(RPMMESS_DEBUG, _("relocating %s to %s\n"), - names[i], newName); - names[i] = newName; - relocated = 1; - } else if (actions) { - actions[i] = FA_SKIPNSTATE; - rpmMessage(RPMMESS_DEBUG, _("excluding %s\n"), names[i]); - } - } - } - - if (relocated) { - headerGetEntry(h, RPMTAG_FILENAMES, NULL, (void **) &origNames, NULL); - headerAddEntry(h, RPMTAG_ORIGFILENAMES, RPM_STRING_ARRAY_TYPE, - origNames, fileCount); - free(origNames); - headerModifyEntry(h, RPMTAG_FILENAMES, RPM_STRING_ARRAY_TYPE, - names, fileCount); - } - - free(names); - - return h; -} - -static int psTrim(rpmProblemSet filter, rpmProblemSet target) { - /* As the problem sets are generated in an order solely dependent - on the ordering of the packages in the transaction, and that - ordering can't be changed, the problem sets must be parallel to - on another. Additionally, the filter set must be a subset of the - target set, given the operations available on transaction set. - This is good, as it lets us perform this trim in linear time, rather - then logarithmic or quadratic. */ - rpmProblem * f, * t; - int gotProblems = 0; - - f = filter->probs; - t = target->probs; - - while ((f - filter->probs) < filter->numProblems) { - if (!f->ignoreProblem) { - f++; - continue; - } - while ((t - target->probs) < target->numProblems) { - if (f->h == t->h && f->type == t->type && t->key == f->key && - XSTRCMP(f->str1, t->str1)) - break; - t++; - gotProblems = 1; - } - - if ((t - target->probs) == target->numProblems) { - /* this can't happen ;-) lets be sane if it doesn though */ - break; - } - - t->ignoreProblem = f->ignoreProblem; - t++, f++; - } - - if ((t - target->probs) < target->numProblems) - gotProblems = 1; - - return gotProblems; -} - -static int sharedCmp(const void * one, const void * two) { - const struct sharedFileInfo * a = one; - const struct sharedFileInfo * b = two; - - if (a->otherPkg < b->otherPkg) - return -1; - else if (a->otherPkg > b->otherPkg) - return 1; - - return 0; -} - -static enum fileActions decideFileFate(const char * filespec, short dbMode, - char * dbMd5, char * dbLink, short newMode, - char * newMd5, char * newLink, int newFlags, - int brokenMd5) { - char buffer[1024]; - char * dbAttr, * newAttr; - enum fileTypes dbWhat, newWhat, diskWhat; - struct stat sb; - int i, rc; - int save = (newFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SAVE; - - if (lstat(filespec, &sb)) { - /* the file doesn't exist on the disk create it unless the new - package has marked it as missingok */ - if (newFlags & RPMFILE_MISSINGOK) { - rpmMessage(RPMMESS_DEBUG, _("%s skipped due to missingok flag\n"), - filespec); - return FA_SKIP; - } else - return FA_CREATE; - } - - diskWhat = whatis(sb.st_mode); - dbWhat = whatis(dbMode); - newWhat = whatis(newMode); - - /* RPM >= 2.3.10 shouldn't create config directories -- we'll ignore - them in older packages as well */ - if (newWhat == XDIR) - return FA_CREATE; - - if (diskWhat != newWhat) { - return save; - } else if (newWhat != dbWhat && diskWhat != dbWhat) { - return save; - } else if (dbWhat != newWhat) { - return FA_CREATE; - } else if (dbWhat != LINK && dbWhat != REG) { - return FA_CREATE; - } - - if (dbWhat == REG) { - if (brokenMd5) - rc = mdfileBroken(filespec, buffer); - else - rc = mdfile(filespec, buffer); - - if (rc) { - /* assume the file has been removed, don't freak */ - return FA_CREATE; - } - dbAttr = dbMd5; - newAttr = newMd5; - } else /* dbWhat == LINK */ { - memset(buffer, 0, sizeof(buffer)); - i = readlink(filespec, buffer, sizeof(buffer) - 1); - if (i == -1) { - /* assume the file has been removed, don't freak */ - return FA_CREATE; - } - dbAttr = dbLink; - newAttr = newLink; - } - - /* this order matters - we'd prefer to CREATE the file if at all - possible in case something else (like the timestamp) has changed */ - - if (!strcmp(dbAttr, buffer)) { - /* this config file has never been modified, so - just replace it */ - return FA_CREATE; - } - - if (!strcmp(dbAttr, newAttr)) { - /* this file is the same in all versions of this package */ - return FA_SKIP; - } - - /* the config file on the disk has been modified, but - the ones in the two packages are different. It would - be nice if RPM was smart enough to at least try and - merge the difference ala CVS, but... */ - - return save; -} - -enum fileTypes whatis(short mode) { - enum fileTypes result; - - if (S_ISDIR(mode)) - result = XDIR; - else if (S_ISCHR(mode)) - result = CDEV; - else if (S_ISBLK(mode)) - result = BDEV; - else if (S_ISLNK(mode)) - result = LINK; - else if (S_ISSOCK(mode)) - result = SOCK; - else if (S_ISFIFO(mode)) - result = PIPE; - else - result = REG; - - return result; -} - -static int filecmp(short mode1, char * md51, char * link1, - short mode2, char * md52, char * link2) { - enum fileTypes what1, what2; - - what1 = whatis(mode1); - what2 = whatis(mode2); - - if (what1 != what2) return 1; - - if (what1 == LINK) - return strcmp(link1, link2); - else if (what1 == REG) - return strcmp(md51, md52); - - return 0; -} - -static int handleInstInstalledFiles(struct fileInfo * fi, rpmdb db, - struct sharedFileInfo * shared, - int sharedCount, int reportConflicts, - rpmProblemSet probs) { - Header h; - int i; - char ** otherMd5s, ** otherLinks; - char * otherStates; - uint_32 * otherFlags, * otherSizes; - uint_16 * otherModes; - int otherFileNum; - int fileNum; - int numReplaced = 0; - - if (!(h = rpmdbGetRecord(db, shared->otherPkg))) - return 1; - - headerGetEntryMinMemory(h, RPMTAG_FILEMD5S, NULL, - (void **) &otherMd5s, NULL); - headerGetEntryMinMemory(h, RPMTAG_FILELINKTOS, NULL, - (void **) &otherLinks, NULL); - headerGetEntryMinMemory(h, RPMTAG_FILESTATES, NULL, - (void **) &otherStates, NULL); - headerGetEntryMinMemory(h, RPMTAG_FILEMODES, NULL, - (void **) &otherModes, NULL); - headerGetEntryMinMemory(h, RPMTAG_FILEFLAGS, NULL, - (void **) &otherFlags, NULL); - headerGetEntryMinMemory(h, RPMTAG_FILESIZES, NULL, - (void **) &otherSizes, NULL); - - fi->replaced = malloc(sizeof(*fi->replaced) * sharedCount); - - for (i = 0; i < sharedCount; i++, shared++) { - otherFileNum = shared->otherFileNum; - fileNum = shared->pkgFileNum; - if (otherStates[otherFileNum] == RPMFILE_STATE_NORMAL) { - if (filecmp(otherModes[otherFileNum], - otherMd5s[otherFileNum], - otherLinks[otherFileNum], - fi->fmodes[fileNum], - fi->fmd5s[fileNum], - fi->flinks[fileNum])) { - if (reportConflicts) - psAppend(probs, RPMPROB_FILE_CONFLICT, fi->ap->key, - fi->ap->h, fi->fl[fileNum], h,0 ); - if (!(otherFlags[otherFileNum] | fi->fflags[fileNum]) - & RPMFILE_CONFIG) { - if (!shared->isRemoved) - fi->replaced[numReplaced++] = *shared; - } - } - - if ((otherFlags[otherFileNum] | fi->fflags[fileNum]) - & RPMFILE_CONFIG) { - fi->actions[fileNum] = decideFileFate(fi->fl[fileNum], - otherModes[otherFileNum], - otherMd5s[otherFileNum], - otherLinks[otherFileNum], - fi->fmodes[fileNum], - fi->fmd5s[fileNum], - fi->flinks[fileNum], - fi->fflags[fileNum], - !headerIsEntry(h, RPMTAG_RPMVERSION)); - } - - fi->replacedSizes[fileNum] = otherSizes[otherFileNum]; - } - } - - free(otherMd5s); - free(otherLinks); - headerFree(h); - - fi->replaced = realloc(fi->replaced, - sizeof(*fi->replaced) * (numReplaced + 1)); - fi->replaced[numReplaced].otherPkg = 0; - - return 0; -} - -static int handleRmvdInstalledFiles(struct fileInfo * fi, rpmdb db, - struct sharedFileInfo * shared, - int sharedCount) { - Header h; - int otherFileNum; - int fileNum; - char * otherStates; - int i; - - if (!(h = rpmdbGetRecord(db, shared->otherPkg))) - return 1; - - headerGetEntryMinMemory(h, RPMTAG_FILESTATES, NULL, - (void **) &otherStates, NULL); - - for (i = 0; i < sharedCount; i++, shared++) { - otherFileNum = shared->otherFileNum; - fileNum = shared->pkgFileNum; - - if (otherStates[otherFileNum] == RPMFILE_STATE_NORMAL) - fi->actions[fileNum] = FA_SKIP; - } - - headerFree(h); - - return 0; -} - -void handleOverlappedFiles(struct fileInfo * fi, hashTable ht, - rpmProblemSet probs, struct diskspaceInfo * dsl) { - int i, j; - struct fileInfo ** recs; - int numRecs; - int otherPkgNum, otherFileNum; - struct stat sb; - char mdsum[50]; - int rc; - struct diskspaceInfo * ds = NULL; - uint_32 fixupSize = 0; - - for (i = 0; i < fi->fc; i++) { - if (fi->actions[i] == FA_SKIP || fi->actions[i] == FA_SKIPNSTATE) - continue; - - if (dsl) { - ds = dsl; - while (ds->block && ds->dev != fi->fps[i].dev) ds++; - if (!ds->block) ds = NULL; - fixupSize = 0; - } - - htGetEntry(ht, &fi->fps[i], (void ***) &recs, &numRecs, NULL); - - /* We need to figure out the current fate of this file. So, - work backwards from this file and look for a final action - we can work against. */ - for (j = 0; recs[j] != fi; j++); - - otherPkgNum = j - 1; - otherFileNum = -1; /* keep gcc quiet */ - while (otherPkgNum >= 0) { - if (recs[otherPkgNum]->type == TR_ADDED) { - /* TESTME: there are more efficient searches in the world... */ - for (otherFileNum = 0; otherFileNum < recs[otherPkgNum]->fc; - otherFileNum++) - if (FP_EQUAL(fi->fps[i], - recs[otherPkgNum]->fps[otherFileNum])) - break; - if ((otherFileNum >= 0) && - (recs[otherPkgNum]->actions[otherFileNum] != FA_UNKNOWN)) - break; - } - otherPkgNum--; - } - - if (fi->type == TR_ADDED && otherPkgNum < 0) { - if (fi->actions[i] == FA_UNKNOWN) { - if ((fi->fflags[i] & RPMFILE_CONFIG) && - !lstat(fi->fl[i], &sb)) { - fi->actions[i] = (fi->fflags[i] & RPMFILE_NOREPLACE) - ? FA_ALTNAME : FA_BACKUP; - } else { - fi->actions[i] = FA_CREATE; - } - } - } else if (fi->type == TR_ADDED) { - if (probs && filecmp(recs[otherPkgNum]->fmodes[otherFileNum], - recs[otherPkgNum]->fmd5s[otherFileNum], - recs[otherPkgNum]->flinks[otherFileNum], - fi->fmodes[i], - fi->fmd5s[i], - fi->flinks[i])) { - psAppend(probs, RPMPROB_NEW_FILE_CONFLICT, fi->ap->key, - fi->ap->h, fi->fl[i], recs[otherPkgNum]->ap->h, 0); - } - - fixupSize = recs[otherPkgNum]->fsizes[otherFileNum]; - - /* FIXME: is this right??? it locks us into the config - file handling choice we already made, which may very - well be exactly right. What about noreplace files?? */ - fi->actions[i] = FA_CREATE; - } else if (fi->type == TR_REMOVED && otherPkgNum >= 0) { - fi->actions[i] = FA_SKIP; - } else if (fi->type == TR_REMOVED) { - if (fi->actions[i] != FA_SKIP && fi->actions[i] != FA_SKIPNSTATE && - fi->fstates[i] == RPMFILE_STATE_NORMAL ) { - if (S_ISREG(fi->fmodes[i]) && - (fi->fflags[i] & RPMFILE_CONFIG)) { - rc = mdfile(fi->fl[i], mdsum); - if (!rc && strcmp(fi->fmd5s[i], mdsum)) { - fi->actions[i] = FA_BACKUP; - } else { - /* FIXME: config files may need to be saved */ - fi->actions[i] = FA_REMOVE; - } - } else { - fi->actions[i] = FA_REMOVE; - } - } - } - - if (ds) { - uint_32 s = BLOCK_ROUND(fi->fsizes[i], ds->block); - - switch (fi->actions[i]) { - case FA_BACKUP: - case FA_SAVE: - case FA_ALTNAME: - ds->needed += s; - break; - - /* FIXME: If a two packages share a file (same md5sum), and - that file is being replaced on disk, will ds->needed get - decremented twice? Quite probably! */ - case FA_CREATE: - ds->needed += s; - ds->needed -= BLOCK_ROUND(fi->replacedSizes[i], ds->block); - break; - - case FA_REMOVE: - ds->needed -= s; - break; - - default: - break; - } - - ds->needed -= BLOCK_ROUND(fixupSize, ds->block); - } - } -} - -static int ensureOlder(rpmdb db, Header new, int dbOffset, rpmProblemSet probs, - const void * key) { - Header old; - int result, rc = 0; - - old = rpmdbGetRecord(db, dbOffset); - if (old == NULL) return 1; - - result = rpmVersionCompare(old, new); - if (result <= 0) - rc = 0; - else if (result > 0) { - rc = 1; - psAppend(probs, RPMPROB_OLDPACKAGE, key, new, NULL, old, 0); - } - - headerFree(old); - - return rc; -} - -static void skipFiles(struct fileInfo * fi, int noDocs) { - int i, j; - char ** netsharedPaths = NULL, ** nsp; - char ** fileLangs, ** languages, ** lang; - char * oneLang[2] = { NULL, NULL }; - int freeLanguages = 0; - char * chptr; - - if (!noDocs) - noDocs = rpmExpandNumeric("%{_excludedocs}"); - - { const char *tmpPath = rpmExpand("%{_netsharedpath}", NULL); - if (tmpPath && *tmpPath != '%') - netsharedPaths = splitString(tmpPath, strlen(tmpPath), ':'); - xfree(tmpPath); - } - - if (!headerGetEntry(fi->h, RPMTAG_FILELANGS, NULL, (void **) &fileLangs, - NULL)) - fileLangs = NULL; - - if ((chptr = getenv("LINGUAS"))) { - languages = splitString(chptr, strlen(chptr), ':'); - freeLanguages = 1; - } else if ((oneLang[0] = getenv("LANG"))) { - languages = oneLang; - } else { - oneLang[0] = "en"; - languages = oneLang; - } - - for (i = 0; i < fi->fc; i++) { - if (fi->actions[i] == FA_SKIP || fi->actions[i] == FA_SKIPNSTATE) - continue; - - /* netsharedPaths are not relative to the current root (though - they do need to take package relocations into account) */ - for (nsp = netsharedPaths; nsp && *nsp; nsp++) { - j = strlen(*nsp); - if (!strncmp(fi->fl[i], *nsp, j) && - (fi->fl[i][j] == '\0' || - fi->fl[i][j] == '/')) - break; - } - - if (nsp && *nsp) { - fi->actions[i] = FA_SKIPNSTATE; - continue; - } - - if (fileLangs && languages && *fileLangs[i]) { - for (lang = languages; *lang; lang++) { - const char *l, *le; - for (l = fileLangs[i]; *l; l = le) { - for (le = l; *le && *le != '|'; le++) - ; - if ((le-l) > 0 && !strncmp(*lang, l, (le-l))) - goto lingo; - if (*le == '|') le++; /* skip over | */ - } - } - lingo: - if (!*lang) { - fi->actions[i] = FA_SKIPNSTATE; - continue; - } - } - - if (noDocs && (fi->fflags[i] & RPMFILE_DOC)) - fi->actions[i] = FA_SKIPNSTATE; - } - - if (netsharedPaths) freeSplitString(netsharedPaths); - if (fileLangs) free(fileLangs); - if (freeLanguages) freeSplitString(languages); -} diff --git a/lib/uninstall.c b/lib/uninstall.c index 8b5a17069..ab5474a70 100644 --- a/lib/uninstall.c +++ b/lib/uninstall.c @@ -8,16 +8,65 @@ #include "misc.h" #include "rpmdb.h" -static char * SCRIPT_PATH = "PATH=/sbin:/bin:/usr/sbin:/usr/bin:" - "/usr/X11R6/bin"; +static char * SCRIPT_PATH = "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin"; static int removeFile(char * file, unsigned int flags, short mode, - enum fileActions action); -static int runScript(Header h, const char * root, int progArgc, const char ** progArgv, - const char * script, int arg1, int arg2, FD_t errfd); + enum fileActions action) +{ + int rc = 0; + char * newfile; + + switch (action) { + + case FA_BACKUP: + newfile = alloca(strlen(file) + 20); + strcpy(newfile, file); + strcat(newfile, ".rpmsave"); + if (rename(file, newfile)) { + rpmError(RPMERR_RENAME, _("rename of %s to %s failed: %s"), + file, newfile, strerror(errno)); + rc = 1; + } + break; + + case FA_REMOVE: + if (S_ISDIR(mode)) { + if (rmdir(file)) { + if (errno == ENOTEMPTY) + rpmError(RPMERR_RMDIR, + _("cannot remove %s - directory not empty"), + file); + else + rpmError(RPMERR_RMDIR, _("rmdir of %s failed: %s"), + file, strerror(errno)); + rc = 1; + } + } else { + if (unlink(file)) { + if (errno != ENOENT || !(flags & RPMFILE_MISSINGOK)) { + rpmError(RPMERR_UNLINK, + _("removal of %s failed: %s"), + file, strerror(errno)); + } + rc = 1; + } + } + break; + case FA_UNKNOWN: + case FA_CREATE: + case FA_SAVE: + case FA_SKIP: + case FA_SKIPNSTATE: + case FA_ALTNAME: + break; + } + + return 0; +} int removeBinaryPackage(char * prefix, rpmdb db, unsigned int offset, - int flags, enum fileActions * actions, FD_t scriptFd) { + int flags, enum fileActions * actions, FD_t scriptFd) +{ Header h; int i; int fileCount; @@ -143,7 +192,8 @@ int removeBinaryPackage(char * prefix, rpmdb db, unsigned int offset, } static int runScript(Header h, const char * root, int progArgc, const char ** progArgv, - const char * script, int arg1, int arg2, FD_t errfd) { + const char * script, int arg1, int arg2, FD_t errfd) +{ const char ** argv; int argc; const char ** prefixes = NULL; @@ -294,7 +344,8 @@ static int runScript(Header h, const char * root, int progArgc, const char ** pr } int runInstScript(const char * root, Header h, int scriptTag, int progTag, - int arg, int norunScripts, FD_t err) { + int arg, int norunScripts, FD_t err) +{ void ** programArgv; int programArgc; const char ** argv; @@ -322,62 +373,10 @@ int runInstScript(const char * root, Header h, int scriptTag, int progTag, return rc; } -static int removeFile(char * file, unsigned int flags, short mode, - enum fileActions action) { - int rc = 0; - char * newfile; - - switch (action) { - - case FA_BACKUP: - newfile = alloca(strlen(file) + 20); - strcpy(newfile, file); - strcat(newfile, ".rpmsave"); - if (rename(file, newfile)) { - rpmError(RPMERR_RENAME, _("rename of %s to %s failed: %s"), - file, newfile, strerror(errno)); - rc = 1; - } - break; - - case FA_REMOVE: - if (S_ISDIR(mode)) { - if (rmdir(file)) { - if (errno == ENOTEMPTY) - rpmError(RPMERR_RMDIR, - _("cannot remove %s - directory not empty"), - file); - else - rpmError(RPMERR_RMDIR, _("rmdir of %s failed: %s"), - file, strerror(errno)); - rc = 1; - } - } else { - if (unlink(file)) { - if (errno != ENOENT || !(flags & RPMFILE_MISSINGOK)) { - rpmError(RPMERR_UNLINK, - _("removal of %s failed: %s"), - file, strerror(errno)); - } - rc = 1; - } - } - break; - case FA_UNKNOWN: - case FA_CREATE: - case FA_SAVE: - case FA_SKIP: - case FA_SKIPNSTATE: - case FA_ALTNAME: - break; - } - - return 0; -} - static int handleOneTrigger(const char * root, rpmdb db, int sense, Header sourceH, Header triggeredH, int arg1correction, int arg2, - char * triggersAlreadyRun, FD_t scriptFd) { + char * triggersAlreadyRun, FD_t scriptFd) +{ const char ** triggerNames; const char ** triggerVersions; const char ** triggerScripts; @@ -457,7 +456,8 @@ static int handleOneTrigger(const char * root, rpmdb db, int sense, Header sourc } int runTriggers(const char * root, rpmdb db, int sense, Header h, - int countCorrection, FD_t scriptFd) { + int countCorrection, FD_t scriptFd) +{ char * packageName; dbiIndexSet matches, otherMatches; Header triggeredH; @@ -495,7 +495,8 @@ int runTriggers(const char * root, rpmdb db, int sense, Header h, } int runImmedTriggers(const char * root, rpmdb db, int sense, Header h, - int countCorrection, FD_t scriptFd) { + int countCorrection, FD_t scriptFd) +{ int rc = 0; dbiIndexSet matches; char ** triggerNames;