2
* \file lib/transaction.c
8
#include <rpmmacro.h> /* XXX for rpmExpand */
14
#include "misc.h" /* XXX stripTrailingChar, splitString, currentDirectory */
17
/*@-redecl -exportheadervar@*/
18
extern const char * chroot_prefix;
19
/*@=redecl =exportheadervar@*/
21
/* XXX FIXME: merge with existing (broken?) tests in system.h */
22
/* portability fiddles */
23
#if STATFS_IN_SYS_STATVFS
24
# include <sys/statvfs.h>
26
# if STATFS_IN_SYS_VFS
29
# if STATFS_IN_SYS_MOUNT
30
# include <sys/mount.h>
32
# if STATFS_IN_SYS_STATFS
33
# include <sys/statfs.h>
41
/*@access FD_t@*/ /* XXX compared with NULL */
42
/*@access Header@*/ /* XXX compared with NULL */
43
/*@access dbiIndexSet@*/
45
/*@access rpmTransactionSet@*/
48
/*@access rpmProblemSet@*/
49
/*@access rpmProblem@*/
51
struct diskspaceInfo {
52
dev_t dev; /*!< file system device number. */
53
signed long bneeded; /*!< no. of blocks needed. */
54
signed long ineeded; /*!< no. of inodes needed. */
55
int bsize; /*!< file system block size. */
56
signed long bavail; /*!< no. of blocks available. */
57
signed long iavail; /*!< no. of inodes available. */
60
/* Adjust for root only reserved space. On linux e2fs, this is 5%. */
61
#define adj_fs_blocks(_nb) (((_nb) * 21) / 20)
63
/* argon thought a shift optimization here was a waste of time... he's
65
#define BLOCK_ROUND(size, block) (((size) + (block) - 1) / (block))
67
#define XSTRCMP(a, b) ((!(a) && !(b)) || ((a) && (b) && !strcmp((a), (b))))
69
static /*@null@*/ void * freeFl(rpmTransactionSet ts,
70
/*@only@*/ /*@null@*/ TFI_t flList)
78
for (oc = 0, fi = flList; oc < ts->orderCount; oc++, fi++)
80
flList = _free(flList);
86
void rpmtransSetScriptFd(rpmTransactionSet ts, FD_t fd)
88
ts->scriptFd = (fd ? fdLink(fd, "rpmtransSetScriptFd") : NULL);
91
int rpmtransGetKeys(const rpmTransactionSet ts, const void *** ep, int * nep)
95
if (nep) *nep = ts->orderCount;
100
*ep = e = xmalloc(ts->orderCount * sizeof(*e));
101
for (oc = 0; oc < ts->orderCount; oc++, e++) {
102
switch (ts->order[oc].type) {
104
if (ts->addedPackages.list) {
105
struct availablePackage * alp;
106
alp = ts->addedPackages.list + ts->order[oc].u.addedIndex;
113
/*@-mods@*/ /* FIX: double indirection. */
123
static rpmProblemSet psCreate(void)
128
probs = xmalloc(sizeof(*probs)); /* XXX memory leak */
129
probs->numProblems = probs->numProblemsAlloced = 0;
135
static void psAppend(rpmProblemSet probs, rpmProblemType type,
136
const struct availablePackage * alp,
137
const char * dn, const char *bn,
138
Header altH, unsigned long ulong1)
139
/*@modifies probs, alp @*/
144
if (probs->numProblems == probs->numProblemsAlloced) {
145
if (probs->numProblemsAlloced)
146
probs->numProblemsAlloced *= 2;
148
probs->numProblemsAlloced = 2;
149
probs->probs = xrealloc(probs->probs,
150
probs->numProblemsAlloced * sizeof(*probs->probs));
153
p = probs->probs + probs->numProblems++;
159
p->ignoreProblem = 0;
163
t = xmalloc((dn ? strlen(dn) : 0) + (bn ? strlen(bn) : 0) + 1);
164
if (dn) t = stpcpy(t, dn);
165
if (bn) t = stpcpy(t, bn);
170
p->h = headerLink(alp->h);
172
t = xmalloc(strlen(alp->name) +
173
strlen(alp->version) +
174
strlen(alp->release) + sizeof("--"));
175
t = stpcpy(t, alp->name);
177
t = stpcpy(t, alp->version);
179
t = stpcpy(t, alp->release);
186
const char * n, * v, * r;
187
(void) headerNVR(altH, &n, &v, &r);
189
t = xmalloc(strlen(n) + strlen(v) + strlen(r) + sizeof("--"));
199
static int archOkay(Header h)
205
/* make sure we're trying to install this on the proper architecture */
206
(void) headerGetEntry(h, RPMTAG_ARCH, &type, (void **) &pkgArch, &count);
208
if (type == RPM_INT8_TYPE) {
212
/* old arch handling */
213
rpmGetArchInfo(NULL, &archNum);
214
pkgArchNum = pkgArch;
215
if (archNum != *pkgArchNum) {
221
/* new arch handling */
222
if (!rpmMachineScore(RPM_MACHTABLE_INSTARCH, pkgArch)) {
230
static int osOkay(Header h)
236
/* make sure we're trying to install this on the proper os */
237
(void) headerGetEntry(h, RPMTAG_OS, &type, (void **) &pkgOs, &count);
239
if (type == RPM_INT8_TYPE) {
240
/* v1 packages and v2 packages both used improper OS numbers, so just
241
deal with it hope things work */
246
/* new os handling */
247
if (!rpmMachineScore(RPM_MACHTABLE_INSTOS, pkgOs)) {
255
void rpmProblemSetFree(rpmProblemSet probs)
259
for (i = 0; i < probs->numProblems; i++) {
260
rpmProblem p = probs->probs + i;
261
p->h = headerFree(p->h);
262
p->pkgNEVR = _free(p->pkgNEVR);
263
p->altNEVR = _free(p->altNEVR);
264
p->str1 = _free(p->str1);
269
static /*@observer@*/ const char *const ftstring (fileTypes ft)
273
case XDIR: return "directory";
274
case CDEV: return "char dev";
275
case BDEV: return "block dev";
276
case LINK: return "link";
277
case SOCK: return "sock";
278
case PIPE: return "fifo/pipe";
279
case REG: return "file";
280
default: return "unknown file type";
285
static fileTypes whatis(uint_16 mode)
288
if (S_ISDIR(mode)) return XDIR;
289
if (S_ISCHR(mode)) return CDEV;
290
if (S_ISBLK(mode)) return BDEV;
291
if (S_ISLNK(mode)) return LINK;
292
if (S_ISSOCK(mode)) return SOCK;
293
if (S_ISFIFO(mode)) return PIPE;
297
#define alloca_strdup(_s) strcpy(alloca(strlen(_s)+1), (_s))
300
* Relocate files in header.
301
* @todo multilib file dispositions need to be checked.
302
* @param ts transaction set
303
* @param fi transaction element file info
304
* @param alp available package
305
* @param origH package header
306
* @param actions file dispositions
307
* @return header with relocated files
309
static Header relocateFileList(const rpmTransactionSet ts, TFI_t fi,
310
struct availablePackage * alp,
311
Header origH, fileAction * actions)
312
/*@modifies ts, fi, alp, origH, actions @*/
317
HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
318
static int _printed = 0;
319
rpmProblemSet probs = ts->probs;
320
int allowBadRelocate = (ts->ignoreSet & RPMPROB_FILTER_FORCERELOCATE);
321
rpmRelocation * rawRelocations = alp->relocs;
322
rpmRelocation * relocations = NULL;
324
const char ** validRelocations;
325
rpmTagType validType;
327
const char ** baseNames;
328
const char ** dirNames;
330
int_32 * newDirIndexes;
333
uint_32 * fFlags = NULL;
334
uint_16 * fModes = NULL;
340
int haveRelocatedFile = 0;
345
if (!hge(origH, RPMTAG_PREFIXES, &validType,
346
(void **) &validRelocations, &numValid))
351
while (rawRelocations[numRelocations].newPath ||
352
rawRelocations[numRelocations].oldPath)
356
* If no relocations are specified (usually the case), then return the
357
* original header. If there are prefixes, however, then INSTPREFIXES
358
* should be added, but, since relocateFileList() can be called more
359
* than once for the same header, don't bother if already present.
361
if (rawRelocations == NULL || numRelocations == 0) {
363
if (!headerIsEntry(origH, RPMTAG_INSTPREFIXES))
364
(void) hae(origH, RPMTAG_INSTPREFIXES,
365
validType, validRelocations, numValid);
366
validRelocations = hfd(validRelocations, validType);
368
/* XXX FIXME multilib file actions need to be checked. */
369
return headerLink(origH);
373
h = headerCopy(origH);
375
h = headerLink(origH);
378
relocations = alloca(sizeof(*relocations) * numRelocations);
380
/* Build sorted relocation list from raw relocations. */
381
for (i = 0; i < numRelocations; i++) {
385
* Default relocations (oldPath == NULL) are handled in the UI,
388
if (rawRelocations[i].oldPath == NULL) continue; /* XXX can't happen */
390
/* FIXME: Trailing /'s will confuse us greatly. Internal ones will
391
too, but those are more trouble to fix up. :-( */
392
t = alloca_strdup(rawRelocations[i].oldPath);
393
relocations[i].oldPath = (t[0] == '/' && t[1] == '\0')
395
: stripTrailingChar(t, '/');
397
/* An old path w/o a new path is valid, and indicates exclusion */
398
if (rawRelocations[i].newPath) {
401
t = alloca_strdup(rawRelocations[i].newPath);
402
relocations[i].newPath = (t[0] == '/' && t[1] == '\0')
404
: stripTrailingChar(t, '/');
406
/*@-nullpass@*/ /* FIX: relocations[i].oldPath == NULL */
407
/* Verify that the relocation's old path is in the header. */
408
for (j = 0; j < numValid; j++)
409
if (!strcmp(validRelocations[j], relocations[i].oldPath))
410
/*@innerbreak@*/ break;
411
/* XXX actions check prevents problem from being appended twice. */
412
if (j == numValid && !allowBadRelocate && actions)
413
psAppend(probs, RPMPROB_BADRELOCATE, alp,
414
relocations[i].oldPath, NULL, NULL, 0);
416
strlen(relocations[i].newPath) - strlen(relocations[i].oldPath);
422
relocations[i].newPath = NULL;
426
/* stupid bubble sort, but it's probably faster here */
427
for (i = 0; i < numRelocations; i++) {
430
for (j = 1; j < numRelocations; j++) {
431
rpmRelocation tmpReloc;
432
if (relocations[j - 1].oldPath == NULL || /* XXX can't happen */
433
relocations[j ].oldPath == NULL || /* XXX can't happen */
434
strcmp(relocations[j - 1].oldPath, relocations[j].oldPath) <= 0)
436
tmpReloc = relocations[j - 1];
437
relocations[j - 1] = relocations[j];
438
relocations[j] = tmpReloc;
441
if (!madeSwap) break;
446
rpmMessage(RPMMESS_DEBUG, _("========== relocations\n"));
447
for (i = 0; i < numRelocations; i++) {
448
if (relocations[i].oldPath == NULL) continue; /* XXX can't happen */
449
if (relocations[i].newPath == NULL)
450
rpmMessage(RPMMESS_DEBUG, _("%5d exclude %s\n"),
451
i, relocations[i].oldPath);
453
rpmMessage(RPMMESS_DEBUG, _("%5d relocate %s -> %s\n"),
454
i, relocations[i].oldPath, relocations[i].newPath);
458
/* Add relocation values to the header */
460
const char ** actualRelocations;
463
actualRelocations = xmalloc(numValid * sizeof(*actualRelocations));
465
for (i = 0; i < numValid; i++) {
466
for (j = 0; j < numRelocations; j++) {
467
if (relocations[j].oldPath == NULL || /* XXX can't happen */
468
strcmp(validRelocations[i], relocations[j].oldPath))
470
/* On install, a relocate to NULL means skip the path. */
471
if (relocations[j].newPath) {
472
actualRelocations[numActual] = relocations[j].newPath;
475
/*@innerbreak@*/ break;
477
if (j == numRelocations) {
478
actualRelocations[numActual] = validRelocations[i];
484
(void) hae(h, RPMTAG_INSTPREFIXES, RPM_STRING_ARRAY_TYPE,
485
(void **) actualRelocations, numActual);
487
actualRelocations = _free(actualRelocations);
488
validRelocations = hfd(validRelocations, validType);
491
(void) hge(h, RPMTAG_BASENAMES, NULL, (void **) &baseNames, &fileCount);
492
(void) hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &dirIndexes, NULL);
493
(void) hge(h, RPMTAG_DIRNAMES, NULL, (void **) &dirNames, &dirCount);
494
(void) hge(h, RPMTAG_FILEFLAGS, NULL, (void **) &fFlags, NULL);
495
(void) hge(h, RPMTAG_FILEMODES, NULL, (void **) &fModes, NULL);
497
skipDirList = alloca(dirCount * sizeof(*skipDirList));
498
memset(skipDirList, 0, dirCount * sizeof(*skipDirList));
500
newDirIndexes = alloca(sizeof(*newDirIndexes) * fileCount);
501
memcpy(newDirIndexes, dirIndexes, sizeof(*newDirIndexes) * fileCount);
502
dirIndexes = newDirIndexes;
505
* For all relocations, we go through sorted file/relocation lists
506
* backwards so that /usr/local relocations take precedence over /usr
510
/* Relocate individual paths. */
512
for (i = fileCount - 1; i >= 0; i--) {
517
* If only adding libraries of different arch into an already
518
* installed package, skip all other files.
520
if (alp->multiLib && !isFileMULTILIB((fFlags[i]))) {
522
actions[i] = FA_SKIPMULTILIB;
523
rpmMessage(RPMMESS_DEBUG, _("excluding multilib path %s%s\n"),
524
dirNames[dirIndexes[i]], baseNames[i]);
530
strlen(dirNames[dirIndexes[i]]) + strlen(baseNames[i]) + 1;
531
if (len >= fileAlloced) {
532
fileAlloced = len * 2;
533
fn = xrealloc(fn, fileAlloced);
536
fnlen = stpcpy( stpcpy(fn, dirNames[dirIndexes[i]]), baseNames[i]) - fn;
539
* See if this file path needs relocating.
542
* XXX FIXME: Would a bsearch of the (already sorted)
543
* relocation list be a good idea?
545
for (j = numRelocations - 1; j >= 0; j--) {
546
if (relocations[j].oldPath == NULL) continue; /* XXX can't happen */
547
len = strcmp(relocations[j].oldPath, "/")
548
? strlen(relocations[j].oldPath)
554
* Only subdirectories or complete file paths may be relocated. We
555
* don't check for '\0' as our directory names all end in '/'.
557
if (!(fn[len] == '/' || fnlen == len))
560
if (strncmp(relocations[j].oldPath, fn, len))
562
/*@innerbreak@*/ break;
566
ft = whatis(fModes[i]);
568
/* On install, a relocate to NULL means skip the path. */
569
if (relocations[j].newPath == NULL) {
571
/* Start with the parent, looking for directory to exclude. */
572
for (j = dirIndexes[i]; j < dirCount; j++) {
573
len = strlen(dirNames[j]) - 1;
574
while (len > 0 && dirNames[j][len-1] == '/') len--;
577
if (strncmp(fn, dirNames[j], fnlen))
579
/*@innerbreak@*/ break;
585
actions[i] = FA_SKIPNSTATE;
586
rpmMessage(RPMMESS_DEBUG, _("excluding %s %s\n"),
592
/* Relocation on full paths only, please. */
593
if (fnlen != len) continue;
596
rpmMessage(RPMMESS_DEBUG, _("relocating %s to %s\n"),
597
fn, relocations[j].newPath);
600
strcpy(fn, relocations[j].newPath);
601
{ char * te = strrchr(fn, '/');
603
if (te > fn) te++; /* root is special */
606
te = fn + strlen(fn);
607
/*@-nullpass -nullderef@*/ /* LCL: te != NULL here. */
608
if (strcmp(baseNames[i], te)) /* basename changed too? */
609
baseNames[i] = alloca_strdup(te);
610
*te = '\0'; /* terminate new directory name */
611
/*@=nullpass =nullderef@*/
614
/* Does this directory already exist in the directory list? */
615
for (j = 0; j < dirCount; j++) {
616
if (fnlen != strlen(dirNames[j]))
618
if (strncmp(fn, dirNames[j], fnlen))
620
/*@innerbreak@*/ break;
628
/* Creating new paths is a pita */
629
if (!haveRelocatedFile) {
630
const char ** newDirList;
632
haveRelocatedFile = 1;
633
newDirList = xmalloc((dirCount + 1) * sizeof(*newDirList));
634
for (j = 0; j < dirCount; j++)
635
newDirList[j] = alloca_strdup(dirNames[j]);
636
dirNames = hfd(dirNames, RPM_STRING_ARRAY_TYPE);
637
dirNames = newDirList;
639
dirNames = xrealloc(dirNames,
640
sizeof(*dirNames) * (dirCount + 1));
643
dirNames[dirCount] = alloca_strdup(fn);
644
dirIndexes[i] = dirCount;
648
/* Finish off by relocating directories. */
649
for (i = dirCount - 1; i >= 0; i--) {
650
for (j = numRelocations - 1; j >= 0; j--) {
652
if (relocations[j].oldPath == NULL) continue; /* XXX can't happen */
653
len = strcmp(relocations[j].oldPath, "/")
654
? strlen(relocations[j].oldPath)
657
if (len && strncmp(relocations[j].oldPath, dirNames[i], len))
661
* Only subdirectories or complete file paths may be relocated. We
662
* don't check for '\0' as our directory names all end in '/'.
664
if (dirNames[i][len] != '/')
667
if (relocations[j].newPath) { /* Relocate the path */
668
const char * s = relocations[j].newPath;
669
char * t = alloca(strlen(s) + strlen(dirNames[i]) - len + 1);
671
(void) stpcpy( stpcpy(t, s) , dirNames[i] + len);
673
rpmMessage(RPMMESS_DEBUG,
674
_("relocating directory %s to %s\n"), dirNames[i], t);
681
/* Save original filenames in header and replace (relocated) filenames. */
688
(void) hge(h, RPMTAG_BASENAMES, &t, &p, &c);
689
(void) hae(h, RPMTAG_ORIGBASENAMES, t, p, c);
693
(void) hge(h, RPMTAG_DIRNAMES, &t, &p, &c);
694
(void) hae(h, RPMTAG_ORIGDIRNAMES, t, p, c);
698
(void) hge(h, RPMTAG_DIRINDEXES, &t, &p, &c);
699
(void) hae(h, RPMTAG_ORIGDIRINDEXES, t, p, c);
702
(void) hme(h, RPMTAG_BASENAMES, RPM_STRING_ARRAY_TYPE,
703
baseNames, fileCount);
704
fi->bnl = hfd(fi->bnl, RPM_STRING_ARRAY_TYPE);
705
(void) hge(h, RPMTAG_BASENAMES, NULL, (void **) &fi->bnl, &fi->fc);
707
(void) hme(h, RPMTAG_DIRNAMES, RPM_STRING_ARRAY_TYPE,
709
fi->dnl = hfd(fi->dnl, RPM_STRING_ARRAY_TYPE);
710
(void) hge(h, RPMTAG_DIRNAMES, NULL, (void **) &fi->dnl, &fi->dc);
712
(void) hme(h, RPMTAG_DIRINDEXES, RPM_INT32_TYPE,
713
dirIndexes, fileCount);
714
(void) hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &fi->dil, NULL);
717
baseNames = hfd(baseNames, RPM_STRING_ARRAY_TYPE);
718
dirNames = hfd(dirNames, RPM_STRING_ARRAY_TYPE);
725
* As the problem sets are generated in an order solely dependent
726
* on the ordering of the packages in the transaction, and that
727
* ordering can't be changed, the problem sets must be parallel to
728
* one another. Additionally, the filter set must be a subset of the
729
* target set, given the operations available on transaction set.
730
* This is good, as it lets us perform this trim in linear time, rather
731
* then logarithmic or quadratic.
733
static int psTrim(rpmProblemSet filter, rpmProblemSet target)
734
/*@modifies target @*/
736
rpmProblem f = filter->probs;
737
rpmProblem t = target->probs;
740
while ((f - filter->probs) < filter->numProblems) {
741
if (!f->ignoreProblem) {
745
while ((t - target->probs) < target->numProblems) {
746
/*@-nullpass@*/ /* LCL: looks good to me */
747
if (f->h == t->h && f->type == t->type && t->key == f->key &&
748
XSTRCMP(f->str1, t->str1))
749
/*@innerbreak@*/ break;
755
if ((t - target->probs) == target->numProblems) {
756
/* this can't happen ;-) lets be sane if it doesn though */
760
t->ignoreProblem = f->ignoreProblem;
764
if ((t - target->probs) < target->numProblems)
770
static int sharedCmp(const void * one, const void * two)
773
const struct sharedFileInfo * a = one;
774
const struct sharedFileInfo * b = two;
776
if (a->otherPkg < b->otherPkg)
778
else if (a->otherPkg > b->otherPkg)
784
static fileAction decideFileFate(const char * dirName,
785
const char * baseName, short dbMode,
786
const char * dbMd5, const char * dbLink, short newMode,
787
const char * newMd5, const char * newLink, int newFlags,
788
int brokenMd5, rpmtransFlags transFlags)
792
const char * dbAttr, * newAttr;
793
fileTypes dbWhat, newWhat, diskWhat;
796
int save = (newFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SAVE;
797
char * filespec = alloca(strlen(dirName) + strlen(baseName) + 1);
799
(void) stpcpy( stpcpy(filespec, dirName), baseName);
801
if (lstat(filespec, &sb)) {
803
* The file doesn't exist on the disk. Create it unless the new
804
* package has marked it as missingok, or allfiles is requested.
806
if (!(transFlags & RPMTRANS_FLAG_ALLFILES) &&
807
(newFlags & RPMFILE_MISSINGOK)) {
808
rpmMessage(RPMMESS_DEBUG, _("%s skipped due to missingok flag\n"),
816
diskWhat = whatis(sb.st_mode);
817
dbWhat = whatis(dbMode);
818
newWhat = whatis(newMode);
820
/* RPM >= 2.3.10 shouldn't create config directories -- we'll ignore
821
them in older packages as well */
822
if (newWhat == XDIR) {
826
if (diskWhat != newWhat) {
828
} else if (newWhat != dbWhat && diskWhat != dbWhat) {
830
} else if (dbWhat != newWhat) {
832
} else if (dbWhat != LINK && dbWhat != REG) {
838
rc = mdfileBroken(filespec, buffer);
840
rc = mdfile(filespec, buffer);
843
/* assume the file has been removed, don't freak */
848
} else /* dbWhat == LINK */ {
849
memset(buffer, 0, sizeof(buffer));
850
i = readlink(filespec, buffer, sizeof(buffer) - 1);
852
/* assume the file has been removed, don't freak */
859
/* this order matters - we'd prefer to CREATE the file if at all
860
possible in case something else (like the timestamp) has changed */
862
if (!strcmp(dbAttr, buffer)) {
863
/* this config file has never been modified, so just replace it */
867
if (!strcmp(dbAttr, newAttr)) {
868
/* this file is the same in all versions of this package */
873
* The config file on the disk has been modified, but
874
* the ones in the two packages are different. It would
875
* be nice if RPM was smart enough to at least try and
876
* merge the difference ala CVS, but...
881
static int filecmp(short mode1, const char * md51, const char * link1,
882
short mode2, const char * md52, const char * link2)
885
fileTypes what1 = whatis(mode1);
886
fileTypes what2 = whatis(mode2);
888
if (what1 != what2) return 1;
891
return strcmp(link1, link2);
892
else if (what1 == REG)
893
return strcmp(md51, md52);
898
static int handleInstInstalledFiles(TFI_t fi, /*@null@*/ rpmdb db,
899
struct sharedFileInfo * shared,
900
int sharedCount, int reportConflicts,
902
rpmtransFlags transFlags)
903
/*@modifies fi, db, probs @*/
906
HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
907
rpmTagType oltype, omtype;
910
const char ** otherMd5s;
911
const char ** otherLinks;
912
const char * otherStates;
913
uint_32 * otherFlags;
914
uint_32 * otherSizes;
915
uint_16 * otherModes;
918
rpmdbMatchIterator mi;
920
mi = rpmdbInitIterator(db, RPMDBI_PACKAGES, &shared->otherPkg, sizeof(shared->otherPkg));
921
h = rpmdbNextIterator(mi);
923
mi = rpmdbFreeIterator(mi);
927
(void) hge(h, RPMTAG_FILEMD5S, &omtype, (void **) &otherMd5s, NULL);
928
(void) hge(h, RPMTAG_FILELINKTOS, &oltype, (void **) &otherLinks, NULL);
929
(void) hge(h, RPMTAG_FILESTATES, NULL, (void **) &otherStates, NULL);
930
(void) hge(h, RPMTAG_FILEMODES, NULL, (void **) &otherModes, NULL);
931
(void) hge(h, RPMTAG_FILEFLAGS, NULL, (void **) &otherFlags, NULL);
932
(void) hge(h, RPMTAG_FILESIZES, NULL, (void **) &otherSizes, NULL);
934
fi->replaced = xmalloc(sharedCount * sizeof(*fi->replaced));
936
for (i = 0; i < sharedCount; i++, shared++) {
937
int otherFileNum, fileNum;
938
otherFileNum = shared->otherFileNum;
939
fileNum = shared->pkgFileNum;
941
/* XXX another tedious segfault, assume file state normal. */
942
if (otherStates && otherStates[otherFileNum] != RPMFILE_STATE_NORMAL)
945
if (XFA_SKIPPING(fi->actions[fileNum]))
948
if (filecmp(otherModes[otherFileNum],
949
otherMd5s[otherFileNum],
950
otherLinks[otherFileNum],
953
fi->flinks[fileNum])) {
955
psAppend(probs, RPMPROB_FILE_CONFLICT, fi->ap,
956
fi->dnl[fi->dil[fileNum]], fi->bnl[fileNum], h, 0);
957
if (!(otherFlags[otherFileNum] | fi->fflags[fileNum])
960
if (!shared->isRemoved)
961
fi->replaced[numReplaced++] = *shared;
966
if ((otherFlags[otherFileNum] | fi->fflags[fileNum]) & RPMFILE_CONFIG) {
967
fi->actions[fileNum] = decideFileFate(
968
fi->dnl[fi->dil[fileNum]],
970
otherModes[otherFileNum],
971
otherMd5s[otherFileNum],
972
otherLinks[otherFileNum],
977
!headerIsEntry(h, RPMTAG_RPMVERSION),
981
fi->replacedSizes[fileNum] = otherSizes[otherFileNum];
984
otherMd5s = hfd(otherMd5s, omtype);
985
otherLinks = hfd(otherLinks, oltype);
986
mi = rpmdbFreeIterator(mi);
988
fi->replaced = xrealloc(fi->replaced, /* XXX memory leak */
989
sizeof(*fi->replaced) * (numReplaced + 1));
990
fi->replaced[numReplaced].otherPkg = 0;
995
static int handleRmvdInstalledFiles(TFI_t fi, /*@null@*/ rpmdb db,
996
struct sharedFileInfo * shared,
998
/*@modifies fi, db @*/
1000
HGE_t hge = fi->hge;
1002
const char * otherStates;
1005
rpmdbMatchIterator mi;
1007
mi = rpmdbInitIterator(db, RPMDBI_PACKAGES,
1008
&shared->otherPkg, sizeof(shared->otherPkg));
1009
h = rpmdbNextIterator(mi);
1011
mi = rpmdbFreeIterator(mi);
1015
(void) hge(h, RPMTAG_FILESTATES, NULL, (void **) &otherStates, NULL);
1017
for (i = 0; i < sharedCount; i++, shared++) {
1018
int otherFileNum, fileNum;
1019
otherFileNum = shared->otherFileNum;
1020
fileNum = shared->pkgFileNum;
1022
if (otherStates[otherFileNum] != RPMFILE_STATE_NORMAL)
1025
fi->actions[fileNum] = FA_SKIP;
1028
mi = rpmdbFreeIterator(mi);
1034
* Update disk space needs on each partition for this package.
1036
static void handleOverlappedFiles(TFI_t fi, hashTable ht,
1037
rpmProblemSet probs, struct diskspaceInfo * dsl)
1038
/*@modifies fi, probs, dsl @*/
1041
struct diskspaceInfo * ds = NULL;
1042
uint_32 fixupSize = 0;
1043
char * filespec = NULL;
1044
int fileSpecAlloced = 0;
1046
for (i = 0; i < fi->fc; i++) {
1047
int otherPkgNum, otherFileNum;
1051
if (XFA_SKIPPING(fi->actions[i]))
1054
j = strlen(fi->dnl[fi->dil[i]]) + strlen(fi->bnl[i]) + 1;
1055
if (j > fileSpecAlloced) {
1056
fileSpecAlloced = j * 2;
1057
filespec = xrealloc(filespec, fileSpecAlloced);
1060
(void) stpcpy( stpcpy( filespec, fi->dnl[fi->dil[i]]), fi->bnl[i]);
1064
while (ds->bsize && ds->dev != fi->fps[i].entry->dev) ds++;
1065
if (!ds->bsize) ds = NULL;
1070
* Retrieve all records that apply to this file. Note that the
1071
* file info records were built in the same order as the packages
1072
* will be installed and removed so the records for an overlapped
1073
* files will be sorted in exactly the same order.
1075
(void) htGetEntry(ht, &fi->fps[i], (const void ***) &recs, &numRecs, NULL);
1078
* If this package is being added, look only at other packages
1079
* being added -- removed packages dance to a different tune.
1080
* If both this and the other package are being added, overlapped
1081
* files must be identical (or marked as a conflict). The
1082
* disposition of already installed config files leads to
1083
* a small amount of extra complexity.
1085
* If this package is being removed, then there are two cases that
1086
* need to be worried about:
1087
* If the other package is being added, then skip any overlapped files
1088
* so that this package removal doesn't nuke the overlapped files
1089
* that were just installed.
1090
* If both this and the other package are being removed, then each
1091
* file removal from preceding packages needs to be skipped so that
1092
* the file removal occurs only on the last occurence of an overlapped
1093
* file in the transaction set.
1097
/* Locate this overlapped file in the set of added/removed packages. */
1098
for (j = 0; j < numRecs && recs[j] != fi; j++)
1101
/* Find what the previous disposition of this file was. */
1102
otherFileNum = -1; /* keep gcc quiet */
1103
for (otherPkgNum = j - 1; otherPkgNum >= 0; otherPkgNum--) {
1104
/* Added packages need only look at other added packages. */
1105
if (fi->type == TR_ADDED && recs[otherPkgNum]->type != TR_ADDED)
1108
/* TESTME: there are more efficient searches in the world... */
1109
for (otherFileNum = 0; otherFileNum < recs[otherPkgNum]->fc;
1112
/* If the addresses are the same, so are the values. */
1113
if ((fi->fps + i) == (recs[otherPkgNum]->fps + otherFileNum))
1114
/*@innerbreak@*/ break;
1116
/* Otherwise, compare fingerprints by value. */
1117
/*@-nullpass@*/ /* LCL: looks good to me */
1118
if (FP_EQUAL(fi->fps[i], recs[otherPkgNum]->fps[otherFileNum]))
1119
/*@innerbreak@*/ break;
1123
/* XXX is this test still necessary? */
1124
if (recs[otherPkgNum]->actions[otherFileNum] != FA_UNKNOWN)
1125
/*@innerbreak@*/ break;
1131
if (otherPkgNum < 0) {
1132
/* XXX is this test still necessary? */
1133
if (fi->actions[i] != FA_UNKNOWN)
1135
if ((fi->fflags[i] & RPMFILE_CONFIG) &&
1136
!lstat(filespec, &sb)) {
1137
/* Here is a non-overlapped pre-existing config file. */
1138
fi->actions[i] = (fi->fflags[i] & RPMFILE_NOREPLACE)
1139
? FA_ALTNAME : FA_BACKUP;
1141
fi->actions[i] = FA_CREATE;
1146
/* Mark added overlapped non-identical files as a conflict. */
1147
if (probs && filecmp(recs[otherPkgNum]->fmodes[otherFileNum],
1148
recs[otherPkgNum]->fmd5s[otherFileNum],
1149
recs[otherPkgNum]->flinks[otherFileNum],
1153
psAppend(probs, RPMPROB_NEW_FILE_CONFLICT, fi->ap,
1154
filespec, NULL, recs[otherPkgNum]->ap->h, 0);
1157
/* Try to get the disk accounting correct even if a conflict. */
1158
fixupSize = recs[otherPkgNum]->fsizes[otherFileNum];
1160
if ((fi->fflags[i] & RPMFILE_CONFIG) && !lstat(filespec, &sb)) {
1161
/* Here is an overlapped pre-existing config file. */
1162
fi->actions[i] = (fi->fflags[i] & RPMFILE_NOREPLACE)
1163
? FA_ALTNAME : FA_SKIP;
1165
fi->actions[i] = FA_CREATE;
1169
if (otherPkgNum >= 0) {
1170
/* Here is an overlapped added file we don't want to nuke. */
1171
if (recs[otherPkgNum]->actions[otherFileNum] != FA_ERASE) {
1172
/* On updates, don't remove files. */
1173
fi->actions[i] = FA_SKIP;
1176
/* Here is an overlapped removed file: skip in previous. */
1177
recs[otherPkgNum]->actions[otherFileNum] = FA_SKIP;
1179
if (XFA_SKIPPING(fi->actions[i]))
1181
if (fi->fstates && fi->fstates[i] != RPMFILE_STATE_NORMAL)
1183
if (!(S_ISREG(fi->fmodes[i]) && (fi->fflags[i] & RPMFILE_CONFIG))) {
1184
fi->actions[i] = FA_ERASE;
1188
/* Here is a pre-existing modified config file that needs saving. */
1190
if (!mdfile(filespec, mdsum) && strcmp(fi->fmd5s[i], mdsum)) {
1191
fi->actions[i] = FA_BACKUP;
1195
fi->actions[i] = FA_ERASE;
1200
uint_32 s = BLOCK_ROUND(fi->fsizes[i], ds->bsize);
1202
switch (fi->actions[i]) {
1211
* FIXME: If two packages share a file (same md5sum), and
1212
* that file is being replaced on disk, will ds->bneeded get
1213
* decremented twice? Quite probably!
1217
ds->bneeded -= BLOCK_ROUND(fi->replacedSizes[i], ds->bsize);
1229
ds->bneeded -= BLOCK_ROUND(fixupSize, ds->bsize);
1232
if (filespec) free(filespec);
1235
static int ensureOlder(struct availablePackage * alp, Header old,
1236
rpmProblemSet probs)
1237
/*@modifies alp, probs @*/
1241
if (old == NULL) return 1;
1243
result = rpmVersionCompare(old, alp->h);
1246
else if (result > 0) {
1248
psAppend(probs, RPMPROB_OLDPACKAGE, alp, NULL, NULL, old, 0);
1254
static void skipFiles(const rpmTransactionSet ts, TFI_t fi)
1257
int noDocs = (ts->transFlags & RPMTRANS_FLAG_NODOCS);
1258
char ** netsharedPaths = NULL;
1259
const char ** languages;
1260
const char * dn, * bn;
1261
int dnlen, bnlen, ix;
1268
noDocs = rpmExpandNumeric("%{_excludedocs}");
1270
{ const char *tmpPath = rpmExpand("%{_netsharedpath}", NULL);
1271
if (tmpPath && *tmpPath != '%')
1272
netsharedPaths = splitString(tmpPath, strlen(tmpPath), ':');
1273
tmpPath = _free(tmpPath);
1276
s = rpmExpand("%{_install_langs}", NULL);
1277
if (!(s && *s != '%'))
1280
languages = (const char **) splitString(s, strlen(s), ':');
1285
/* Compute directory refcount, skip directory if now empty. */
1286
drc = alloca(fi->dc * sizeof(*drc));
1287
memset(drc, 0, fi->dc * sizeof(*drc));
1288
dff = alloca(fi->dc * sizeof(*dff));
1289
memset(dff, 0, fi->dc * sizeof(*dff));
1291
for (i = 0; i < fi->fc; i++) {
1302
/* Don't bother with skipped files */
1303
if (XFA_SKIPPING(fi->actions[i])) {
1309
* Skip net shared paths.
1310
* Net shared paths are not relative to the current root (though
1311
* they do need to take package relocations into account).
1313
for (nsp = netsharedPaths; nsp && *nsp; nsp++) {
1318
if (strncmp(dn, *nsp, len)) continue;
1319
/* Only directories or complete file paths can be net shared */
1320
if (!(dn[len] == '/' || dn[len] == '\0')) continue;
1322
if (len < (dnlen + bnlen)) continue;
1323
if (strncmp(dn, *nsp, dnlen)) continue;
1324
if (strncmp(bn, (*nsp) + dnlen, bnlen)) continue;
1325
len = dnlen + bnlen;
1326
/* Only directories or complete file paths can be net shared */
1327
if (!((*nsp)[len] == '/' || (*nsp)[len] == '\0')) continue;
1330
/*@innerbreak@*/ break;
1334
drc[ix]--; dff[ix] = 1;
1335
fi->actions[i] = FA_SKIPNETSHARED;
1340
* Skip i18n language specific files.
1342
if (fi->flangs && languages && *fi->flangs[i]) {
1343
const char **lang, *l, *le;
1344
for (lang = languages; *lang != '\0'; lang++) {
1345
if (!strcmp(*lang, "all"))
1346
/*@innerbreak@*/ break;
1347
for (l = fi->flangs[i]; *l != '\0'; l = le) {
1348
for (le = l; *le != '\0' && *le != '|'; le++)
1350
if ((le-l) > 0 && !strncmp(*lang, l, (le-l)))
1351
/*@innerbreak@*/ break;
1352
if (*le == '|') le++; /* skip over | */
1355
/*@innerbreak@*/ break;
1357
if (*lang == NULL) {
1358
drc[ix]--; dff[ix] = 1;
1359
fi->actions[i] = FA_SKIPNSTATE;
1365
* Skip documentation if requested.
1367
if (noDocs && (fi->fflags[i] & RPMFILE_DOC)) {
1368
drc[ix]--; dff[ix] = 1;
1369
fi->actions[i] = FA_SKIPNSTATE;
1374
/* Skip (now empty) directories that had skipped files. */
1375
for (j = 0; j < fi->dc; j++) {
1377
if (drc[j]) continue; /* dir still has files. */
1378
if (!dff[j]) continue; /* dir was not emptied here. */
1380
/* Find parent directory and basename. */
1381
dn = fi->dnl[j]; dnlen = strlen(dn) - 1;
1382
bn = dn + dnlen; bnlen = 0;
1383
while (bn > dn && bn[-1] != '/') {
1389
/* If explicitly included in the package, skip the directory. */
1390
for (i = 0; i < fi->fc; i++) {
1393
if (XFA_SKIPPING(fi->actions[i]))
1395
if (whatis(fi->fmodes[i]) != XDIR)
1397
dir = fi->dnl[fi->dil[i]];
1398
if (strlen(dir) != dnlen)
1400
if (strncmp(dir, dn, dnlen))
1402
if (strlen(fi->bnl[i]) != bnlen)
1404
if (strncmp(fi->bnl[i], bn, bnlen))
1406
rpmMessage(RPMMESS_DEBUG, _("excluding directory %s\n"), dn);
1407
fi->actions[i] = FA_SKIPNSTATE;
1408
/*@innerbreak@*/ break;
1412
if (netsharedPaths) freeSplitString(netsharedPaths);
1413
#ifdef DYING /* XXX freeFi will deal with this later. */
1414
fi->flangs = _free(fi->flangs);
1416
if (languages) freeSplitString((char **)languages);
1420
* Iterator across transaction elements, forward on install, backward on erase.
1422
struct tsIterator_s {
1423
/*@kept@*/ rpmTransactionSet ts; /*!< transaction set. */
1424
int reverse; /*!< reversed traversal? */
1425
int ocsave; /*!< last returned iterator index. */
1426
int oc; /*!< iterator index. */
1430
* Return transaction element order count.
1431
* @param a transaction element iterator
1432
* @return element order count
1434
static int tsGetOc(void * a)
1437
struct tsIterator_s * iter = a;
1438
int oc = iter->ocsave;
1443
* Return transaction element available package pointer.
1444
* @param a transaction element iterator
1445
* @return available package pointer
1447
static /*@dependent@*/ struct availablePackage * tsGetAlp(void * a)
1450
struct tsIterator_s * iter = a;
1451
struct availablePackage * alp = NULL;
1452
int oc = iter->ocsave;
1455
rpmTransactionSet ts = iter->ts;
1456
TFI_t fi = ts->flList + oc;
1457
if (ts->addedPackages.list && fi->type == TR_ADDED)
1458
alp = ts->addedPackages.list + ts->order[oc].u.addedIndex;
1464
* Destroy transaction element iterator.
1465
* @param a transaction element iterator
1466
* @return NULL always
1468
static /*@null@*/ void * tsFreeIterator(/*@only@*//*@null@*/ const void * a)
1475
* Create transaction element iterator.
1476
* @param a transaction set
1477
* @return transaction element iterator
1479
static void * tsInitIterator(/*@kept@*/ const void * a)
1482
rpmTransactionSet ts = (void *)a;
1483
struct tsIterator_s * iter = NULL;
1485
iter = xcalloc(1, sizeof(*iter));
1487
iter->reverse = ((ts->transFlags & RPMTRANS_FLAG_REVERSE) ? 1 : 0);
1488
iter->oc = (iter->reverse ? (ts->orderCount - 1) : 0);
1489
iter->ocsave = iter->oc;
1494
* Return next transaction element's file info.
1495
* @param a file info iterator
1496
* @return next index, -1 on termination
1498
static /*@dependent@*/ TFI_t tsNextIterator(void * a)
1501
struct tsIterator_s * iter = a;
1502
rpmTransactionSet ts = iter->ts;
1506
if (iter->reverse) {
1507
if (iter->oc >= 0) oc = iter->oc--;
1509
if (iter->oc < ts->orderCount) oc = iter->oc++;
1513
fi = ts->flList + oc;
1517
#define NOTIFY(_ts, _al) if ((_ts)->notify) (void) (_ts)->notify _al
1519
int rpmRunTransactions( rpmTransactionSet ts,
1520
rpmCallbackFunction notify, rpmCallbackData notifyData,
1521
rpmProblemSet okProbs, rpmProblemSet * newProbs,
1522
rpmtransFlags transFlags, rpmprobFilterFlags ignoreSet)
1526
struct availablePackage * alp;
1530
int totalFileCount = 0;
1533
struct diskspaceInfo * dip;
1534
struct sharedFileInfo * shared, * sharedList;
1539
fingerPrintCache fpc;
1540
struct psm_s psmbuf;
1541
PSM_t psm = &psmbuf;
1544
/* FIXME: what if the same package is included in ts twice? */
1546
ts->transFlags = transFlags;
1547
if (ts->transFlags & RPMTRANS_FLAG_NOSCRIPTS)
1548
ts->transFlags |= (_noTransScripts | _noTransTriggers);
1549
if (ts->transFlags & RPMTRANS_FLAG_NOTRIGGERS)
1550
ts->transFlags |= _noTransTriggers;
1552
/* XXX MULTILIB is broken, as packages can and do execute /sbin/ldconfig. */
1553
if (ts->transFlags & (RPMTRANS_FLAG_JUSTDB | RPMTRANS_FLAG_MULTILIB))
1554
ts->transFlags |= (_noTransScripts | _noTransTriggers);
1556
ts->notify = notify;
1557
ts->notifyData = notifyData;
1559
ts->probs = *newProbs = psCreate();
1561
ts->ignoreSet = ignoreSet;
1562
ts->currDir = _free(ts->currDir);
1563
ts->currDir = currentDirectory();
1565
if (ts->rpmdb) ts->rpmdb->db_chrootDone = 0;
1566
ts->id = (int_32) time(NULL);
1568
memset(psm, 0, sizeof(*psm));
1573
/* Get available space on mounted file systems. */
1574
if (!(ts->ignoreSet & RPMPROB_FILTER_DISKSPACE) &&
1575
!rpmGetFilesystemList(&ts->filesystems, &ts->filesystemCount)) {
1578
ts->di = _free(ts->di);
1579
dip = ts->di = xcalloc(sizeof(*ts->di), ts->filesystemCount + 1);
1581
for (i = 0; (i < ts->filesystemCount) && dip; i++) {
1582
#if STATFS_IN_SYS_STATVFS
1584
memset(&sfb, 0, sizeof(sfb));
1585
if (statvfs(ts->filesystems[i], &sfb))
1589
/* This platform has the 4-argument version of the statfs call. The last two
1590
* should be the size of struct statfs and 0, respectively. The 0 is the
1591
* filesystem type, and is always 0 when statfs is called on a mounted
1592
* filesystem, as we're doing.
1594
memset(&sfb, 0, sizeof(sfb));
1595
if (statfs(ts->filesystems[i], &sfb, sizeof(sfb), 0))
1597
memset(&sfb, 0, sizeof(sfb));
1598
if (statfs(ts->filesystems[i], &sfb))
1604
ts->di[i].bsize = sfb.f_bsize;
1605
ts->di[i].bneeded = 0;
1606
ts->di[i].ineeded = 0;
1607
#ifdef STATFS_HAS_F_BAVAIL
1608
ts->di[i].bavail = sfb.f_bavail;
1610
/* FIXME: the statfs struct doesn't have a member to tell how many blocks are
1611
* available for non-superusers. f_blocks - f_bfree is probably too big, but
1612
* it's about all we can do.
1614
ts->di[i].bavail = sfb.f_blocks - sfb.f_bfree;
1616
/* XXX Avoid FAT and other file systems that have not inodes. */
1617
ts->di[i].iavail = !(sfb.f_ffree == 0 && sfb.f_files == 0)
1620
(void) stat(ts->filesystems[i], &sb);
1621
ts->di[i].dev = sb.st_dev;
1625
if (dip) ts->di[i].bsize = 0;
1629
hdrs = alloca(sizeof(*hdrs) * ts->addedPackages.size);
1632
/* ===============================================
1633
* For packages being installed:
1634
* - verify package arch/os.
1635
* - verify package epoch:version-release is newer.
1637
* For packages being removed:
1640
/* The ordering doesn't matter here */
1641
if (ts->addedPackages.list != NULL)
1642
for (alp = ts->addedPackages.list;
1643
(alp - ts->addedPackages.list) < ts->addedPackages.size;
1646
if (!archOkay(alp->h) && !(ts->ignoreSet & RPMPROB_FILTER_IGNOREARCH))
1647
psAppend(ts->probs, RPMPROB_BADARCH, alp, NULL, NULL, NULL, 0);
1649
if (!osOkay(alp->h) && !(ts->ignoreSet & RPMPROB_FILTER_IGNOREOS))
1650
psAppend(ts->probs, RPMPROB_BADOS, alp, NULL, NULL, NULL, 0);
1652
if (!(ts->ignoreSet & RPMPROB_FILTER_OLDPACKAGE)) {
1653
rpmdbMatchIterator mi;
1655
mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_NAME, alp->name, 0);
1656
while ((oldH = rpmdbNextIterator(mi)) != NULL)
1657
(void) ensureOlder(alp, oldH, ts->probs);
1658
mi = rpmdbFreeIterator(mi);
1661
/* XXX multilib should not display "already installed" problems */
1662
if (!(ts->ignoreSet & RPMPROB_FILTER_REPLACEPKG) && !alp->multiLib) {
1663
rpmdbMatchIterator mi;
1664
mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_NAME, alp->name, 0);
1665
(void) rpmdbSetIteratorRE(mi, RPMTAG_VERSION,
1666
RPMMIRE_DEFAULT, alp->version);
1667
(void) rpmdbSetIteratorRE(mi, RPMTAG_RELEASE,
1668
RPMMIRE_DEFAULT, alp->release);
1670
while (rpmdbNextIterator(mi) != NULL) {
1671
psAppend(ts->probs, RPMPROB_PKG_INSTALLED, alp,
1672
NULL, NULL, NULL, 0);
1673
/*@innerbreak@*/ break;
1675
mi = rpmdbFreeIterator(mi);
1678
totalFileCount += alp->filesCount;
1682
/* FIXME: it seems a bit silly to read in all of these headers twice */
1683
/* The ordering doesn't matter here */
1684
if (ts->numRemovedPackages > 0) {
1685
rpmdbMatchIterator mi;
1689
mi = rpmdbInitIterator(ts->rpmdb, RPMDBI_PACKAGES, NULL, 0);
1690
(void) rpmdbAppendIterator(mi, ts->removedPackages, ts->numRemovedPackages);
1691
while ((h = rpmdbNextIterator(mi)) != NULL) {
1692
if (headerGetEntry(h, RPMTAG_BASENAMES, NULL, NULL, &fileCount))
1693
totalFileCount += fileCount;
1695
mi = rpmdbFreeIterator(mi);
1698
/* ===============================================
1699
* Initialize file list:
1701
ts->flEntries = ts->addedPackages.size + ts->numRemovedPackages;
1702
ts->flList = xcalloc(ts->flEntries, sizeof(*ts->flList));
1705
* FIXME?: we'd be better off assembling one very large file list and
1706
* calling fpLookupList only once. I'm not sure that the speedup is
1707
* worth the trouble though.
1709
tsi = tsInitIterator(ts);
1710
while ((fi = tsNextIterator(tsi)) != NULL) {
1712
fi->magic = TFIMAGIC;
1714
/* XXX watchout: fi->type must be set for tsGetAlp() to "work" */
1715
fi->type = ts->order[oc].type;
1718
i = ts->order[oc].u.addedIndex;
1719
/* XXX watchout: fi->type must be set for tsGetAlp() to "work" */
1720
fi->ap = tsGetAlp(tsi);
1722
loadFi(fi->ap->h, fi);
1725
hdrs[i] = headerLink(fi->h);
1731
/* Allocate file actions (and initialize to FA_UNKNOWN) */
1732
fi->actions = xcalloc(fi->fc, sizeof(*fi->actions));
1733
hdrs[i] = relocateFileList(ts, fi, fi->ap, fi->h, fi->actions);
1735
{ Header foo = relocateFileList(ts, fi, fi->ap, fi->h, fi->actions);
1736
foo = headerFree(foo);
1740
/* Skip netshared paths, not our i18n files, and excluded docs */
1745
fi->record = ts->order[oc].u.removed.dboffset;
1746
{ rpmdbMatchIterator mi;
1748
mi = rpmdbInitIterator(ts->rpmdb, RPMDBI_PACKAGES,
1749
&fi->record, sizeof(fi->record));
1750
if ((fi->h = rpmdbNextIterator(mi)) != NULL)
1751
fi->h = headerLink(fi->h);
1752
mi = rpmdbFreeIterator(mi);
1754
if (fi->h == NULL) {
1758
/* XXX header arg unused. */
1764
fi->fps = xmalloc(fi->fc * sizeof(*fi->fps));
1766
tsi = tsFreeIterator(tsi);
1769
/* Open all database indices before installing. */
1770
(void) rpmdbOpenAll(ts->rpmdb);
1773
if (!ts->chrootDone) {
1775
/*@-unrecog -superuser @*/
1776
(void) chroot(ts->rootDir);
1777
/*@=unrecog =superuser @*/
1779
if (ts->rpmdb) ts->rpmdb->db_chrootDone = 1;
1781
chroot_prefix = ts->rootDir;
1785
ht = htCreate(totalFileCount * 2, 0, 0, fpHashFunction, fpEqual);
1786
fpc = fpCacheCreate(totalFileCount);
1788
/* ===============================================
1789
* Add fingerprint for each file not skipped.
1791
tsi = tsInitIterator(ts);
1792
while ((fi = tsNextIterator(tsi)) != NULL) {
1793
fpLookupList(fpc, fi->dnl, fi->bnl, fi->dil, fi->fc, fi->fps);
1794
for (i = 0; i < fi->fc; i++) {
1795
if (XFA_SKIPPING(fi->actions[i]))
1797
/*@-dependenttrans@*/
1798
htAddEntry(ht, fi->fps + i, fi);
1799
/*@=dependenttrans@*/
1802
tsi = tsFreeIterator(tsi);
1805
NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_START, 6, ts->flEntries,
1806
NULL, ts->notifyData));
1809
/* ===============================================
1810
* Compute file disposition for each package in transaction set.
1812
tsi = tsInitIterator(ts);
1813
while ((fi = tsNextIterator(tsi)) != NULL) {
1814
dbiIndexSet * matches;
1818
NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_PROGRESS, (fi - ts->flList),
1819
ts->flEntries, NULL, ts->notifyData));
1822
if (fi->fc == 0) continue;
1824
/* Extract file info for all files in this package from the database. */
1825
matches = xcalloc(sizeof(*matches), fi->fc);
1826
if (rpmdbFindFpList(ts->rpmdb, fi->fps, matches, fi->fc))
1827
return 1; /* XXX WTFO? */
1830
for (i = 0; i < fi->fc; i++)
1831
numShared += dbiIndexSetCount(matches[i]);
1833
/* Build sorted file info list for this package. */
1834
shared = sharedList = xmalloc((numShared + 1) * sizeof(*sharedList));
1835
for (i = 0; i < fi->fc; i++) {
1837
* Take care not to mark files as replaced in packages that will
1838
* have been removed before we will get here.
1840
for (j = 0; j < dbiIndexSetCount(matches[i]); j++) {
1842
ro = dbiIndexRecordOffset(matches[i], j);
1844
for (k = 0; ro != knownBad && k < ts->orderCount; k++) {
1845
switch (ts->order[k].type) {
1847
if (ts->order[k].u.removed.dboffset == ro)
1855
shared->pkgFileNum = i;
1856
shared->otherPkg = dbiIndexRecordOffset(matches[i], j);
1857
shared->otherFileNum = dbiIndexRecordFileNumber(matches[i], j);
1858
shared->isRemoved = (knownBad == ro);
1861
matches[i] = dbiFreeIndexSet(matches[i]);
1863
numShared = shared - sharedList;
1864
shared->otherPkg = -1;
1865
matches = _free(matches);
1867
/* Sort file info by other package index (otherPkg) */
1868
qsort(sharedList, numShared, sizeof(*shared), sharedCmp);
1870
/* For all files from this package that are in the database ... */
1871
for (i = 0; i < numShared; i = nexti) {
1874
shared = sharedList + i;
1876
/* Find the end of the files in the other package. */
1877
for (nexti = i + 1; nexti < numShared; nexti++) {
1878
if (sharedList[nexti].otherPkg != shared->otherPkg)
1879
/*@innerbreak@*/ break;
1882
/* Is this file from a package being removed? */
1884
for (j = 0; j < ts->numRemovedPackages; j++) {
1885
if (ts->removedPackages[j] != shared->otherPkg)
1888
/*@innerbreak@*/ break;
1891
/* Determine the fate of each file. */
1894
(void) handleInstInstalledFiles(fi, ts->rpmdb, shared, nexti - i,
1895
!(beingRemoved || (ts->ignoreSet & RPMPROB_FILTER_REPLACEOLDFILES)),
1896
ts->probs, ts->transFlags);
1900
(void) handleRmvdInstalledFiles(fi, ts->rpmdb, shared, nexti - i);
1907
/* Update disk space needs on each partition for this package. */
1908
handleOverlappedFiles(fi, ht,
1909
((ts->ignoreSet & RPMPROB_FILTER_REPLACENEWFILES)
1910
? NULL : ts->probs), ts->di);
1912
/* Check added package has sufficient space on each partition used. */
1915
if (!(ts->di && fi->fc))
1917
for (i = 0; i < ts->filesystemCount; i++) {
1921
/* XXX Avoid FAT and other file systems that have not inodes. */
1922
if (dip->iavail <= 0)
1925
if (adj_fs_blocks(dip->bneeded) > dip->bavail)
1926
psAppend(ts->probs, RPMPROB_DISKSPACE, fi->ap,
1927
ts->filesystems[i], NULL, NULL,
1928
(adj_fs_blocks(dip->bneeded) - dip->bavail) * dip->bsize);
1930
if (adj_fs_blocks(dip->ineeded) > dip->iavail)
1931
psAppend(ts->probs, RPMPROB_DISKNODES, fi->ap,
1932
ts->filesystems[i], NULL, NULL,
1933
(adj_fs_blocks(dip->ineeded) - dip->iavail));
1940
tsi = tsFreeIterator(tsi);
1942
if (ts->chrootDone) {
1943
/*@-unrecog -superuser @*/
1945
/*@=unrecog =superuser @*/
1947
if (ts->rpmdb) ts->rpmdb->db_chrootDone = 0;
1948
chroot_prefix = NULL;
1949
(void) chdir(ts->currDir);
1953
NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_STOP, 6, ts->flEntries,
1954
NULL, ts->notifyData));
1957
/* ===============================================
1958
* Free unused memory as soon as possible.
1961
tsi = tsInitIterator(ts);
1962
while ((fi = tsNextIterator(tsi)) != NULL) {
1966
fi->fps = _free(fi->fps);
1968
tsi = tsFreeIterator(tsi);
1973
/* ===============================================
1974
* If unfiltered problems exist, free memory and return.
1976
if ((ts->transFlags & RPMTRANS_FLAG_BUILD_PROBS) ||
1977
(ts->probs->numProblems && (!okProbs || psTrim(okProbs, ts->probs))))
1979
*newProbs = ts->probs;
1982
for (alp = ts->addedPackages.list, fi = ts->flList;
1983
(alp - ts->addedPackages.list) < ts->addedPackages.size;
1986
hdrs[alp - ts->addedPackages.list] =
1987
headerFree(hdrs[alp - ts->addedPackages.list]);
1991
ts->flList = freeFl(ts, ts->flList);
1994
return ts->orderCount;
1998
/* ===============================================
1999
* Save removed files before erasing.
2001
if (ts->transFlags & (RPMTRANS_FLAG_DIRSTASH | RPMTRANS_FLAG_REPACKAGE)) {
2002
tsi = tsInitIterator(ts);
2003
while ((fi = tsNextIterator(tsi)) != NULL) {
2009
if (ts->transFlags & RPMTRANS_FLAG_REPACKAGE)
2010
(void) psmStage(psm, PSM_PKGSAVE);
2014
tsi = tsFreeIterator(tsi);
2017
/* ===============================================
2018
* Install and remove packages.
2021
lastFailed = -2; /* erased packages have -1 */
2022
tsi = tsInitIterator(ts);
2023
while ((fi = tsNextIterator(tsi)) != NULL) {
2032
alp = tsGetAlp(tsi);
2033
assert(alp == fi->ap);
2034
i = alp - ts->addedPackages.list;
2036
h = headerLink(fi->h);
2037
if (alp->fd == NULL) {
2038
alp->fd = ts->notify(fi->h, RPMCALLBACK_INST_OPEN_FILE, 0, 0,
2039
alp->key, ts->notifyData);
2044
hdrs[i] = headerFree(hdrs[i]);
2048
/*@-mustmod@*/ /* LCL: segfault */
2049
rpmrc = rpmReadPackageHeader(alp->fd, &h, NULL, NULL, NULL);
2051
if (!(rpmrc == RPMRC_OK || rpmrc == RPMRC_BADSIZE)) {
2052
(void)ts->notify(fi->h, RPMCALLBACK_INST_CLOSE_FILE,
2053
0, 0, alp->key, ts->notifyData);
2058
hdrs[i] = relocateFileList(ts, fi, alp, h, NULL);
2061
Header foo = relocateFileList(ts, fi, alp, h, NULL);
2063
h = headerLink(foo);
2064
foo = headerFree(foo);
2067
if (alp->fd) gotfd = 1;
2072
Header hsave = NULL;
2075
hsave = headerLink(fi->h);
2076
fi->h = headerFree(fi->h);
2079
fi->h = headerLink(hdrs[i]);
2081
fi->h = headerLink(h);
2084
ts->transFlags |= RPMTRANS_FLAG_MULTILIB;
2086
assert(alp == fi->ap);
2087
if (psmStage(psm, PSM_PKGINSTALL)) {
2091
fi->h = headerFree(fi->h);
2093
fi->h = headerLink(hsave);
2094
hsave = headerFree(hsave);
2102
hdrs[i] = headerFree(hdrs[i]);
2108
(void)ts->notify(fi->h, RPMCALLBACK_INST_CLOSE_FILE, 0, 0,
2109
alp->key, ts->notifyData);
2115
/* If install failed, then we shouldn't erase. */
2116
if (ts->order[oc].u.removed.dependsOnIndex == lastFailed)
2119
if (psmStage(psm, PSM_PKGERASE))
2124
(void) rpmdbSync(ts->rpmdb);
2126
tsi = tsFreeIterator(tsi);
2128
ts->flList = freeFl(ts, ts->flList);