1 /** \ingroup rpmtrans payload
3 * Package state machine to handle a package from a transaction set.
16 #include "rpmlead.h" /* writeLead proto */
17 #include "signature.h" /* signature constants */
18 #include "legacy.h" /* XXX buildOrigFileList() */
19 #include "ugid.h" /* XXX unameToUid() and gnameToGid() */
20 #include "misc.h" /* XXX stripTrailingChar() */
21 #include "rpmdb.h" /* XXX for db_chrootDone */
27 /*@access Header@*/ /* compared with NULL */
28 /*@access rpmdbMatchIterator@*/ /* compared with NULL */
29 /*@access FSM_t@*/ /* compared with NULL */
30 /*@access FD_t@*/ /* compared with NULL */
31 /*@access rpmdb@*/ /* compared with NULL */
33 /*@access rpmTransactionSet@*/
38 /*@access rpmDepSet@*/
40 /*@-redecl -declundef -exportheadervar@*/
42 extern const char * chroot_prefix;
43 /*@=redecl =declundef =exportheadervar@*/
45 int rpmVersionCompare(Header first, Header second)
47 const char * one, * two;
48 int_32 * epochOne, * epochTwo;
51 if (!headerGetEntry(first, RPMTAG_EPOCH, NULL, (void **) &epochOne, NULL))
53 if (!headerGetEntry(second, RPMTAG_EPOCH, NULL, (void **) &epochTwo,
57 if (epochOne && !epochTwo)
59 else if (!epochOne && epochTwo)
61 else if (epochOne && epochTwo) {
62 if (*epochOne < *epochTwo)
64 else if (*epochOne > *epochTwo)
68 rc = headerGetEntry(first, RPMTAG_VERSION, NULL, (void **) &one, NULL);
69 rc = headerGetEntry(second, RPMTAG_VERSION, NULL, (void **) &two, NULL);
71 rc = rpmvercmp(one, two);
75 rc = headerGetEntry(first, RPMTAG_RELEASE, NULL, (void **) &one, NULL);
76 rc = headerGetEntry(second, RPMTAG_RELEASE, NULL, (void **) &two, NULL);
78 return rpmvercmp(one, two);
81 char * fiGetNVR(const TFI_t fi)
89 t = xcalloc(1, (fi->name != NULL ? strlen(fi->name) : 0) +
90 (fi->version != NULL ? strlen(fi->version) : 0) +
91 (fi->release != NULL ? strlen(fi->release) : 0) +
94 if (fi->name != NULL) t = stpcpy(t, fi->name);
96 if (fi->version != NULL) t = stpcpy(t, fi->version);
98 if (fi->release != NULL) t = stpcpy(t, fi->release);
104 static /*@observer@*/ const char *const ftstring (fileTypes ft)
108 case XDIR: return "directory";
109 case CDEV: return "char dev";
110 case BDEV: return "block dev";
111 case LINK: return "link";
112 case SOCK: return "sock";
113 case PIPE: return "fifo/pipe";
114 case REG: return "file";
115 default: return "unknown file type";
120 fileTypes whatis(uint_16 mode)
122 if (S_ISDIR(mode)) return XDIR;
123 if (S_ISCHR(mode)) return CDEV;
124 if (S_ISBLK(mode)) return BDEV;
125 if (S_ISLNK(mode)) return LINK;
126 if (S_ISSOCK(mode)) return SOCK;
127 if (S_ISFIFO(mode)) return PIPE;
131 #define alloca_strdup(_s) strcpy(alloca(strlen(_s)+1), (_s))
133 Header relocateFileList(const rpmTransactionSet ts, TFI_t fi,
134 Header origH, fileAction * actions)
139 HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
140 static int _printed = 0;
141 int allowBadRelocate = (ts->ignoreSet & RPMPROB_FILTER_FORCERELOCATE);
142 rpmRelocation * relocations = NULL;
144 const char ** validRelocations;
145 rpmTagType validType;
147 const char ** baseNames;
148 const char ** dirNames;
150 int_32 * newDirIndexes;
153 uint_32 * fFlags = NULL;
154 uint_16 * fModes = NULL;
160 int haveRelocatedFile = 0;
165 if (!hge(origH, RPMTAG_PREFIXES, &validType,
166 (void **) &validRelocations, &numValid))
171 while (fi->relocs[numRelocations].newPath ||
172 fi->relocs[numRelocations].oldPath)
176 * If no relocations are specified (usually the case), then return the
177 * original header. If there are prefixes, however, then INSTPREFIXES
178 * should be added, but, since relocateFileList() can be called more
179 * than once for the same header, don't bother if already present.
181 if (fi->relocs == NULL || numRelocations == 0) {
183 if (!headerIsEntry(origH, RPMTAG_INSTPREFIXES))
184 xx = hae(origH, RPMTAG_INSTPREFIXES,
185 validType, validRelocations, numValid);
186 validRelocations = hfd(validRelocations, validType);
188 /* XXX FIXME multilib file actions need to be checked. */
189 return headerLink(origH, "relocate(return)");
192 h = headerLink(origH, "relocate(orig)");
194 relocations = alloca(sizeof(*relocations) * numRelocations);
196 /* Build sorted relocation list from raw relocations. */
197 for (i = 0; i < numRelocations; i++) {
201 * Default relocations (oldPath == NULL) are handled in the UI,
204 if (fi->relocs[i].oldPath == NULL) continue; /* XXX can't happen */
206 /* FIXME: Trailing /'s will confuse us greatly. Internal ones will
207 too, but those are more trouble to fix up. :-( */
208 t = alloca_strdup(fi->relocs[i].oldPath);
210 relocations[i].oldPath = (t[0] == '/' && t[1] == '\0')
212 : stripTrailingChar(t, '/');
215 /* An old path w/o a new path is valid, and indicates exclusion */
216 if (fi->relocs[i].newPath) {
219 t = alloca_strdup(fi->relocs[i].newPath);
221 relocations[i].newPath = (t[0] == '/' && t[1] == '\0')
223 : stripTrailingChar(t, '/');
226 /*@-nullpass@*/ /* FIX: relocations[i].oldPath == NULL */
227 /* Verify that the relocation's old path is in the header. */
228 for (j = 0; j < numValid; j++)
229 if (!strcmp(validRelocations[j], relocations[i].oldPath))
230 /*@innerbreak@*/ break;
231 /* XXX actions check prevents problem from being appended twice. */
232 if (j == numValid && !allowBadRelocate && actions) {
233 rpmProblemSetAppend(ts->probs, RPMPROB_BADRELOCATE,
234 fiGetNVR(fi), fi->key,
235 relocations[i].oldPath, NULL, NULL, 0);
238 strlen(relocations[i].newPath) - strlen(relocations[i].oldPath);
244 relocations[i].newPath = NULL;
248 /* stupid bubble sort, but it's probably faster here */
249 for (i = 0; i < numRelocations; i++) {
252 for (j = 1; j < numRelocations; j++) {
253 rpmRelocation tmpReloc;
254 if (relocations[j - 1].oldPath == NULL || /* XXX can't happen */
255 relocations[j ].oldPath == NULL || /* XXX can't happen */
256 strcmp(relocations[j - 1].oldPath, relocations[j].oldPath) <= 0)
257 /*@innercontinue@*/ continue;
258 /*@-usereleased@*/ /* LCL: ??? */
259 tmpReloc = relocations[j - 1];
260 relocations[j - 1] = relocations[j];
261 relocations[j] = tmpReloc;
265 if (!madeSwap) break;
270 rpmMessage(RPMMESS_DEBUG, _("========== relocations\n"));
271 for (i = 0; i < numRelocations; i++) {
272 if (relocations[i].oldPath == NULL) continue; /* XXX can't happen */
273 if (relocations[i].newPath == NULL)
274 rpmMessage(RPMMESS_DEBUG, _("%5d exclude %s\n"),
275 i, relocations[i].oldPath);
277 rpmMessage(RPMMESS_DEBUG, _("%5d relocate %s -> %s\n"),
278 i, relocations[i].oldPath, relocations[i].newPath);
282 /* Add relocation values to the header */
284 const char ** actualRelocations;
287 actualRelocations = xmalloc(numValid * sizeof(*actualRelocations));
289 for (i = 0; i < numValid; i++) {
290 for (j = 0; j < numRelocations; j++) {
291 if (relocations[j].oldPath == NULL || /* XXX can't happen */
292 strcmp(validRelocations[i], relocations[j].oldPath))
293 /*@innercontinue@*/ continue;
294 /* On install, a relocate to NULL means skip the path. */
295 if (relocations[j].newPath) {
296 actualRelocations[numActual] = relocations[j].newPath;
299 /*@innerbreak@*/ break;
301 if (j == numRelocations) {
302 actualRelocations[numActual] = validRelocations[i];
308 xx = hae(h, RPMTAG_INSTPREFIXES, RPM_STRING_ARRAY_TYPE,
309 (void **) actualRelocations, numActual);
311 actualRelocations = _free(actualRelocations);
312 validRelocations = hfd(validRelocations, validType);
315 xx = hge(h, RPMTAG_BASENAMES, NULL, (void **) &baseNames, &fileCount);
316 xx = hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &dirIndexes, NULL);
317 xx = hge(h, RPMTAG_DIRNAMES, NULL, (void **) &dirNames, &dirCount);
318 xx = hge(h, RPMTAG_FILEFLAGS, NULL, (void **) &fFlags, NULL);
319 xx = hge(h, RPMTAG_FILEMODES, NULL, (void **) &fModes, NULL);
321 skipDirList = alloca(dirCount * sizeof(*skipDirList));
322 memset(skipDirList, 0, dirCount * sizeof(*skipDirList));
324 newDirIndexes = alloca(sizeof(*newDirIndexes) * fileCount);
325 memcpy(newDirIndexes, dirIndexes, sizeof(*newDirIndexes) * fileCount);
326 dirIndexes = newDirIndexes;
329 * For all relocations, we go through sorted file/relocation lists
330 * backwards so that /usr/local relocations take precedence over /usr
334 /* Relocate individual paths. */
336 for (i = fileCount - 1; i >= 0; i--) {
341 * If only adding libraries of different arch into an already
342 * installed package, skip all other files.
344 if (fi->multiLib && !isFileMULTILIB((fFlags[i]))) {
346 actions[i] = FA_SKIPMULTILIB;
347 rpmMessage(RPMMESS_DEBUG, _("excluding multilib path %s%s\n"),
348 dirNames[dirIndexes[i]], baseNames[i]);
354 strlen(dirNames[dirIndexes[i]]) + strlen(baseNames[i]) + 1;
356 if (len >= fileAlloced) {
357 fileAlloced = len * 2;
358 fn = xrealloc(fn, fileAlloced);
362 fnlen = stpcpy( stpcpy(fn, dirNames[dirIndexes[i]]), baseNames[i]) - fn;
365 * See if this file path needs relocating.
368 * XXX FIXME: Would a bsearch of the (already sorted)
369 * relocation list be a good idea?
371 for (j = numRelocations - 1; j >= 0; j--) {
372 if (relocations[j].oldPath == NULL) /* XXX can't happen */
373 /*@innercontinue@*/ continue;
374 len = strcmp(relocations[j].oldPath, "/")
375 ? strlen(relocations[j].oldPath)
379 /*@innercontinue@*/ continue;
381 * Only subdirectories or complete file paths may be relocated. We
382 * don't check for '\0' as our directory names all end in '/'.
384 if (!(fn[len] == '/' || fnlen == len))
385 /*@innercontinue@*/ continue;
387 if (strncmp(relocations[j].oldPath, fn, len))
388 /*@innercontinue@*/ continue;
389 /*@innerbreak@*/ break;
393 ft = whatis(fModes[i]);
395 /* On install, a relocate to NULL means skip the path. */
396 if (relocations[j].newPath == NULL) {
398 /* Start with the parent, looking for directory to exclude. */
399 for (j = dirIndexes[i]; j < dirCount; j++) {
400 len = strlen(dirNames[j]) - 1;
401 while (len > 0 && dirNames[j][len-1] == '/') len--;
403 /*@innercontinue@*/ continue;
404 if (strncmp(fn, dirNames[j], fnlen))
405 /*@innercontinue@*/ continue;
406 /*@innerbreak@*/ break;
412 actions[i] = FA_SKIPNSTATE;
413 rpmMessage(RPMMESS_DEBUG, _("excluding %s %s\n"),
419 /* Relocation on full paths only, please. */
420 if (fnlen != len) continue;
423 rpmMessage(RPMMESS_DEBUG, _("relocating %s to %s\n"),
424 fn, relocations[j].newPath);
427 strcpy(fn, relocations[j].newPath);
428 { char * te = strrchr(fn, '/');
430 if (te > fn) te++; /* root is special */
433 te = fn + strlen(fn);
434 /*@-nullpass -nullderef@*/ /* LCL: te != NULL here. */
435 if (strcmp(baseNames[i], te)) /* basename changed too? */
436 baseNames[i] = alloca_strdup(te);
437 *te = '\0'; /* terminate new directory name */
438 /*@=nullpass =nullderef@*/
441 /* Does this directory already exist in the directory list? */
442 for (j = 0; j < dirCount; j++) {
443 if (fnlen != strlen(dirNames[j]))
444 /*@innercontinue@*/ continue;
445 if (strncmp(fn, dirNames[j], fnlen))
446 /*@innercontinue@*/ continue;
447 /*@innerbreak@*/ break;
455 /* Creating new paths is a pita */
456 if (!haveRelocatedFile) {
457 const char ** newDirList;
459 haveRelocatedFile = 1;
460 newDirList = xmalloc((dirCount + 1) * sizeof(*newDirList));
461 for (j = 0; j < dirCount; j++)
462 newDirList[j] = alloca_strdup(dirNames[j]);
463 dirNames = hfd(dirNames, RPM_STRING_ARRAY_TYPE);
464 dirNames = newDirList;
466 dirNames = xrealloc(dirNames,
467 sizeof(*dirNames) * (dirCount + 1));
470 dirNames[dirCount] = alloca_strdup(fn);
471 dirIndexes[i] = dirCount;
475 /* Finish off by relocating directories. */
476 for (i = dirCount - 1; i >= 0; i--) {
477 for (j = numRelocations - 1; j >= 0; j--) {
479 if (relocations[j].oldPath == NULL) /* XXX can't happen */
480 /*@innercontinue@*/ continue;
481 len = strcmp(relocations[j].oldPath, "/")
482 ? strlen(relocations[j].oldPath)
485 if (len && strncmp(relocations[j].oldPath, dirNames[i], len))
486 /*@innercontinue@*/ continue;
489 * Only subdirectories or complete file paths may be relocated. We
490 * don't check for '\0' as our directory names all end in '/'.
492 if (dirNames[i][len] != '/')
493 /*@innercontinue@*/ continue;
495 if (relocations[j].newPath) { /* Relocate the path */
496 const char * s = relocations[j].newPath;
497 char * t = alloca(strlen(s) + strlen(dirNames[i]) - len + 1);
499 (void) stpcpy( stpcpy(t, s) , dirNames[i] + len);
501 rpmMessage(RPMMESS_DEBUG,
502 _("relocating directory %s to %s\n"), dirNames[i], t);
509 /* Save original filenames in header and replace (relocated) filenames. */
516 xx = hge(h, RPMTAG_BASENAMES, &t, &p, &c);
517 xx = hae(h, RPMTAG_ORIGBASENAMES, t, p, c);
521 xx = hge(h, RPMTAG_DIRNAMES, &t, &p, &c);
522 xx = hae(h, RPMTAG_ORIGDIRNAMES, t, p, c);
526 xx = hge(h, RPMTAG_DIRINDEXES, &t, &p, &c);
527 xx = hae(h, RPMTAG_ORIGDIRINDEXES, t, p, c);
530 xx = hme(h, RPMTAG_BASENAMES, RPM_STRING_ARRAY_TYPE,
531 baseNames, fileCount);
532 fi->bnl = hfd(fi->bnl, RPM_STRING_ARRAY_TYPE);
533 xx = hge(h, RPMTAG_BASENAMES, NULL, (void **) &fi->bnl, &fi->fc);
535 xx = hme(h, RPMTAG_DIRNAMES, RPM_STRING_ARRAY_TYPE,
537 fi->dnl = hfd(fi->dnl, RPM_STRING_ARRAY_TYPE);
538 xx = hge(h, RPMTAG_DIRNAMES, NULL, (void **) &fi->dnl, &fi->dc);
540 xx = hme(h, RPMTAG_DIRINDEXES, RPM_INT32_TYPE,
541 dirIndexes, fileCount);
542 xx = hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &fi->dil, NULL);
545 baseNames = hfd(baseNames, RPM_STRING_ARRAY_TYPE);
546 dirNames = hfd(dirNames, RPM_STRING_ARRAY_TYPE);
552 fnpyKey rpmfiGetKey(TFI_t fi)
554 /*@-compdef -retexpose -usereleased@*/
556 /*@=compdef =retexpose =usereleased@*/
559 TFI_t XrpmfiUnlink(TFI_t fi, const char * msg, const char * fn, unsigned ln)
563 fprintf(stderr, "--> fi %p -- %d %s at %s:%u\n", fi, fi->nrefs, msg, fn, ln);
569 TFI_t XrpmfiLink(TFI_t fi, const char * msg, const char * fn, unsigned ln)
574 fprintf(stderr, "--> fi %p ++ %d %s at %s:%u\n", fi, fi->nrefs, msg, fn, ln);
576 /*@-refcounttrans@*/ return fi; /*@=refcounttrans@*/
579 void loadFi(const rpmTransactionSet ts, TFI_t fi, Header h, int keep_header)
591 /* XXX avoid gcc noise on pointer (4th arg) cast(s) */
592 hge = (keep_header && fi->type == TR_ADDED)
593 ? (HGE_t) headerGetEntryMinMemory : (HGE_t) headerGetEntry;
595 fi->hae = (HAE_t) headerAddEntry;
596 fi->hme = (HME_t) headerModifyEntry;
597 fi->hre = (HRE_t) headerRemoveEntry;
598 fi->hfd = hfd = headerFreeData;
601 if (h && fi->h == NULL) fi->h = headerLink(h, "loadFi");
604 /* Duplicate name-version-release so that headers can be free'd. */
605 rc = hge(fi->h, RPMTAG_NAME, NULL, (void **) &fi->name, NULL);
606 fi->name = xstrdup(fi->name);
607 rc = hge(fi->h, RPMTAG_VERSION, NULL, (void **) &fi->version, NULL);
608 fi->version = xstrdup(fi->version);
609 rc = hge(fi->h, RPMTAG_RELEASE, NULL, (void **) &fi->release, NULL);
610 fi->release = xstrdup(fi->release);
612 /* -1 means not found */
613 rc = hge(fi->h, RPMTAG_EPOCH, NULL, (void **) &uip, NULL);
614 fi->epoch = (rc ? *uip : -1);
616 /* 0 means unknown */
617 rc = hge(fi->h, RPMTAG_ARCHIVESIZE, NULL, (void **) &uip, NULL);
618 fi->archiveSize = (rc ? *uip : 0);
620 if (!hge(fi->h, RPMTAG_BASENAMES, NULL, (void **) &fi->bnl, &fi->fc)) {
626 rc = hge(fi->h, RPMTAG_DIRNAMES, NULL, (void **) &fi->dnl, &fi->dc);
628 rc = hge(fi->h, RPMTAG_DIRINDEXES, NULL, (void **) &fi->dil, NULL);
629 rc = hge(fi->h, RPMTAG_FILEMODES, NULL, (void **) &fi->fmodes, NULL);
630 rc = hge(fi->h, RPMTAG_FILEFLAGS, NULL, (void **) &fi->fflags, NULL);
631 rc = hge(fi->h, RPMTAG_FILESIZES, NULL, (void **) &fi->fsizes, NULL);
633 /* XXX initialized to NULL for TR_ADDED? */
634 rc = hge(fi->h, RPMTAG_FILESTATES, NULL, (void **) &fi->fstates, NULL);
636 fi->action = FA_UNKNOWN;
639 /* actions is initialized earlier for added packages */
640 if (fi->actions == NULL)
641 fi->actions = xcalloc(fi->fc, sizeof(*fi->actions));
643 fi->keep_header = keep_header;
647 CPIO_MAP_PATH | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
648 rc = hge(fi->h, RPMTAG_FILELINKTOS, NULL, (void **) &fi->flinks, NULL);
649 rc = hge(fi->h, RPMTAG_FILELANGS, NULL, (void **) &fi->flangs, NULL);
651 rc = hge(fi->h, RPMTAG_FILEMD5S, NULL, (void **) &fi->fmd5s, NULL);
653 rc = hge(fi->h, RPMTAG_FILEMTIMES, NULL, (void **) &fi->fmtimes, NULL);
654 rc = hge(fi->h, RPMTAG_FILERDEVS, NULL, (void **) &fi->frdevs, NULL);
656 /* 0 makes for noops */
657 fi->replacedSizes = xcalloc(fi->fc, sizeof(*fi->replacedSizes));
659 if (ts != NULL && fi->h != NULL)
660 { Header foo = relocateFileList(ts, fi, fi->h, fi->actions);
661 foo = headerFree(foo, "loadFi TR_ADDED relocate");
664 if (!fi->keep_header) {
665 fi->fmtimes = memcpy(xmalloc(fi->fc * sizeof(*fi->fmtimes)),
666 fi->fmtimes, fi->fc * sizeof(*fi->fmtimes));
667 fi->frdevs = memcpy(xmalloc(fi->fc * sizeof(*fi->frdevs)),
668 fi->frdevs, fi->fc * sizeof(*fi->frdevs));
670 fi->fsizes = memcpy(xmalloc(fi->fc * sizeof(*fi->fsizes)),
671 fi->fsizes, fi->fc * sizeof(*fi->fsizes));
672 fi->fflags = memcpy(xmalloc(fi->fc * sizeof(*fi->fflags)),
673 fi->fflags, fi->fc * sizeof(*fi->fflags));
674 fi->fmodes = memcpy(xmalloc(fi->fc * sizeof(*fi->fmodes)),
675 fi->fmodes, fi->fc * sizeof(*fi->fmodes));
676 /* XXX there's a tedious segfault here for some version(s) of rpm */
678 fi->fstates = memcpy(xmalloc(fi->fc * sizeof(*fi->fstates)),
679 fi->fstates, fi->fc * sizeof(*fi->fstates));
681 fi->fstates = xcalloc(1, fi->fc * sizeof(*fi->fstates));
682 fi->dil = memcpy(xmalloc(fi->fc * sizeof(*fi->dil)),
683 fi->dil, fi->fc * sizeof(*fi->dil));
684 fi->h = headerFree(fi->h, "loadFi TR_ADDED");
690 CPIO_MAP_ABSOLUTE | CPIO_MAP_ADDDOT | CPIO_ALL_HARDLINKS |
691 CPIO_MAP_PATH | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
692 rc = hge(fi->h, RPMTAG_FILEMD5S, NULL, (void **) &fi->fmd5s, NULL);
693 rc = hge(fi->h, RPMTAG_FILELINKTOS, NULL, (void **) &fi->flinks, NULL);
694 fi->fsizes = memcpy(xmalloc(fi->fc * sizeof(*fi->fsizes)),
695 fi->fsizes, fi->fc * sizeof(*fi->fsizes));
696 fi->fflags = memcpy(xmalloc(fi->fc * sizeof(*fi->fflags)),
697 fi->fflags, fi->fc * sizeof(*fi->fflags));
698 fi->fmodes = memcpy(xmalloc(fi->fc * sizeof(*fi->fmodes)),
699 fi->fmodes, fi->fc * sizeof(*fi->fmodes));
700 /* XXX there's a tedious segfault here for some version(s) of rpm */
702 fi->fstates = memcpy(xmalloc(fi->fc * sizeof(*fi->fstates)),
703 fi->fstates, fi->fc * sizeof(*fi->fstates));
705 fi->fstates = xcalloc(1, fi->fc * sizeof(*fi->fstates));
706 fi->dil = memcpy(xmalloc(fi->fc * sizeof(*fi->dil)),
707 fi->dil, fi->fc * sizeof(*fi->dil));
708 fi->h = headerFree(fi->h, "loadFi TR_REMOVED");
713 for (i = 0; i < fi->dc; i++) {
714 if ((len = strlen(fi->dnl[i])) > fi->dnlmax)
719 for (i = 0; i < fi->fc; i++) {
720 if ((len = strlen(fi->bnl[i])) > fi->bnlmax)
730 void freeFi(TFI_t fi)
732 HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
736 if (!fi->keep_header) {
737 fi->fmtimes = hfd(fi->fmtimes, -1);
738 fi->frdevs = hfd(fi->frdevs, -1);
739 fi->fsizes = hfd(fi->fsizes, -1);
740 fi->fflags = hfd(fi->fflags, -1);
741 fi->fmodes = hfd(fi->fmodes, -1);
742 fi->fstates = hfd(fi->fstates, -1);
743 fi->dil = hfd(fi->dil, -1);
747 fi->fsizes = hfd(fi->fsizes, -1);
748 fi->fflags = hfd(fi->fflags, -1);
749 fi->fmodes = hfd(fi->fmodes, -1);
750 fi->fstates = hfd(fi->fstates, -1);
751 fi->dil = hfd(fi->dil, -1);
755 fi->fsm = freeFSM(fi->fsm);
757 fi->apath = _free(fi->apath);
758 fi->fuids = _free(fi->fuids);
759 fi->fgids = _free(fi->fgids);
760 fi->fmapflags = _free(fi->fmapflags);
762 fi->bnl = hfd(fi->bnl, -1);
763 fi->dnl = hfd(fi->dnl, -1);
764 fi->obnl = hfd(fi->obnl, -1);
765 fi->odnl = hfd(fi->odnl, -1);
766 fi->flinks = hfd(fi->flinks, -1);
767 fi->fmd5s = hfd(fi->fmd5s, -1);
768 fi->fuser = hfd(fi->fuser, -1);
769 fi->fgroup = hfd(fi->fgroup, -1);
770 fi->flangs = hfd(fi->flangs, -1);
772 fi->name = _free(fi->name);
773 fi->version = _free(fi->version);
774 fi->release = _free(fi->release);
775 fi->actions = _free(fi->actions);
776 fi->replacedSizes = _free(fi->replacedSizes);
777 fi->replaced = _free(fi->replaced);
779 fi->h = headerFree(fi->h, "freeFi");
781 /*@-nullstate@*/ /* FIX: fi->{name,version,release,actions,...,h} NULL */
786 /*@observer@*/ const char *const fiTypeString(TFI_t fi)
789 case TR_ADDED: return " install";
790 case TR_REMOVED: return " erase";
791 default: return "???";
797 * Macros to be defined from per-header tag values.
798 * @todo Should other macros be added from header when installing a package?
800 /*@observer@*/ /*@unchecked@*/
801 static struct tagMacro {
802 /*@observer@*/ /*@null@*/ const char * macroname; /*!< Macro name to define. */
803 rpmTag tag; /*!< Header tag to use for value. */
805 { "name", RPMTAG_NAME },
806 { "version", RPMTAG_VERSION },
807 { "release", RPMTAG_RELEASE },
808 { "epoch", RPMTAG_EPOCH },
813 * Define per-header macros.
814 * @param fi transaction element file info
818 static int rpmInstallLoadMacros(TFI_t fi, Header h)
819 /*@globals rpmGlobalMacroContext, internalState @*/
820 /*@modifies rpmGlobalMacroContext, internalState @*/
822 HGE_t hge = (HGE_t) fi->hge;
823 struct tagMacro * tagm;
825 /*@unused@*/ void * ptr;
826 /*@unused@*/ const char ** argv;
833 for (tagm = tagMacros; tagm->macroname != NULL; tagm++) {
834 if (!hge(h, tagm->tag, &type, (void **) &body, NULL))
838 sprintf(numbuf, "%d", *body.i32p);
839 addMacro(NULL, tagm->macroname, NULL, numbuf, -1);
840 /*@switchbreak@*/ break;
841 case RPM_STRING_TYPE:
842 addMacro(NULL, tagm->macroname, NULL, body.str, -1);
843 /*@switchbreak@*/ break;
849 case RPM_STRING_ARRAY_TYPE:
850 case RPM_I18NSTRING_TYPE:
852 /*@switchbreak@*/ break;
859 * Copy file data from h to newH.
860 * @param h header from
861 * @param newH header to
862 * @param actions array of file dispositions
863 * @return 0 on success, 1 on failure
865 static int mergeFiles(TFI_t fi, Header h, Header newH)
868 HGE_t hge = (HGE_t)fi->hge;
869 HME_t hme = (HME_t)fi->hme;
870 HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
871 fileAction * actions = fi->actions;
875 int_32 dirNamesCount, dirCount;
876 void * data, * newdata;
877 int_32 * dirIndexes, * newDirIndexes;
878 uint_32 * fileSizes, fileSize;
879 const char ** dirNames;
880 const char ** newDirNames;
881 static rpmTag mergeTags[] = {
891 RPMTAG_FILEGROUPNAME,
892 RPMTAG_FILEVERIFYFLAGS,
899 static rpmTag requireTags[] = {
900 RPMTAG_REQUIRENAME, RPMTAG_REQUIREVERSION, RPMTAG_REQUIREFLAGS,
901 RPMTAG_PROVIDENAME, RPMTAG_PROVIDEVERSION, RPMTAG_PROVIDEFLAGS,
902 RPMTAG_CONFLICTNAME, RPMTAG_CONFLICTVERSION, RPMTAG_CONFLICTFLAGS
905 xx = hge(h, RPMTAG_SIZE, NULL, (void **) &fileSizes, NULL);
906 fileSize = *fileSizes;
907 xx = hge(newH, RPMTAG_FILESIZES, NULL, (void **) &fileSizes, &count);
908 for (i = 0, fc = 0; i < count; i++)
909 if (actions[i] != FA_SKIPMULTILIB) {
911 fileSize += fileSizes[i];
913 xx = hme(h, RPMTAG_SIZE, RPM_INT32_TYPE, &fileSize, 1);
916 for (i = 0; mergeTags[i]; i++) {
917 if (!hge(newH, mergeTags[i], &type, (void **) &data, &count))
922 newdata = xcalloc(fc, sizeof(int_8));
923 for (j = 0, k = 0; j < count; j++)
924 if (actions[j] != FA_SKIPMULTILIB)
925 ((int_8 *) newdata)[k++] = ((int_8 *) data)[j];
926 xx = headerAddOrAppendEntry(h, mergeTags[i], type, newdata, fc);
928 /*@switchbreak@*/ break;
930 newdata = xcalloc(fc, sizeof(int_16));
931 for (j = 0, k = 0; j < count; j++)
932 if (actions[j] != FA_SKIPMULTILIB)
933 ((int_16 *) newdata)[k++] = ((int_16 *) data)[j];
934 xx = headerAddOrAppendEntry(h, mergeTags[i], type, newdata, fc);
936 /*@switchbreak@*/ break;
938 newdata = xcalloc(fc, sizeof(int_32));
939 for (j = 0, k = 0; j < count; j++)
940 if (actions[j] != FA_SKIPMULTILIB)
941 ((int_32 *) newdata)[k++] = ((int_32 *) data)[j];
942 xx = headerAddOrAppendEntry(h, mergeTags[i], type, newdata, fc);
944 /*@switchbreak@*/ break;
945 case RPM_STRING_ARRAY_TYPE:
946 newdata = xcalloc(fc, sizeof(char *));
947 for (j = 0, k = 0; j < count; j++)
948 if (actions[j] != FA_SKIPMULTILIB)
949 ((char **) newdata)[k++] = ((char **) data)[j];
950 xx = headerAddOrAppendEntry(h, mergeTags[i], type, newdata, fc);
952 /*@switchbreak@*/ break;
954 rpmError(RPMERR_DATATYPE, _("Data type %d not supported\n"),
957 /*@notreached@*/ /*@switchbreak@*/ break;
959 data = hfd(data, type);
962 xx = hge(newH, RPMTAG_DIRINDEXES, NULL, (void **) &newDirIndexes, &count);
963 xx = hge(newH, RPMTAG_DIRNAMES, NULL, (void **) &newDirNames, NULL);
964 xx = hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &dirIndexes, NULL);
965 xx = hge(h, RPMTAG_DIRNAMES, NULL, (void **) &data, &dirNamesCount);
967 dirNames = xcalloc(dirNamesCount + fc, sizeof(*dirNames));
968 for (i = 0; i < dirNamesCount; i++)
969 dirNames[i] = ((char **) data)[i];
970 dirCount = dirNamesCount;
971 newdata = xcalloc(fc, sizeof(*newDirIndexes));
972 for (i = 0, k = 0; i < count; i++) {
973 if (actions[i] == FA_SKIPMULTILIB)
975 for (j = 0; j < dirCount; j++)
976 if (!strcmp(dirNames[j], newDirNames[newDirIndexes[i]]))
977 /*@innerbreak@*/ break;
979 dirNames[dirCount++] = newDirNames[newDirIndexes[i]];
980 ((int_32 *) newdata)[k++] = j;
982 xx = headerAddOrAppendEntry(h, RPMTAG_DIRINDEXES, RPM_INT32_TYPE, newdata, fc);
983 if (dirCount > dirNamesCount)
984 xx = headerAddOrAppendEntry(h, RPMTAG_DIRNAMES, RPM_STRING_ARRAY_TYPE,
985 dirNames + dirNamesCount,
986 dirCount - dirNamesCount);
987 data = hfd(data, -1);
988 newDirNames = hfd(newDirNames, -1);
992 for (i = 0; i < 9; i += 3) {
993 const char **Names, **EVR, **newNames, **newEVR;
994 rpmTagType nnt, nvt, rnt;
995 uint_32 *Flags, *newFlags;
996 int Count = 0, newCount = 0;
998 if (!hge(newH, requireTags[i], &nnt, (void **) &newNames, &newCount))
1001 xx = hge(newH, requireTags[i+1], &nvt, (void **) &newEVR, NULL);
1002 xx = hge(newH, requireTags[i+2], NULL, (void **) &newFlags, NULL);
1003 if (hge(h, requireTags[i], &rnt, (void **) &Names, &Count))
1005 xx = hge(h, requireTags[i+1], NULL, (void **) &EVR, NULL);
1006 xx = hge(h, requireTags[i+2], NULL, (void **) &Flags, NULL);
1007 for (j = 0; j < newCount; j++)
1008 for (k = 0; k < Count; k++)
1009 if (!strcmp (newNames[j], Names[k])
1010 && !strcmp (newEVR[j], EVR[k])
1011 && (newFlags[j] & RPMSENSE_SENSEMASK) ==
1012 (Flags[k] & RPMSENSE_SENSEMASK))
1015 /*@innerbreak@*/ break;
1018 for (j = 0, k = 0; j < newCount; j++) {
1019 if (!newNames[j] || !isDependsMULTILIB(newFlags[j]))
1020 /*@innercontinue@*/ continue;
1022 newNames[k] = newNames[j];
1023 newEVR[k] = newEVR[j];
1024 newFlags[k] = newFlags[j];
1029 xx = headerAddOrAppendEntry(h, requireTags[i],
1030 RPM_STRING_ARRAY_TYPE, newNames, k);
1031 xx = headerAddOrAppendEntry(h, requireTags[i+1],
1032 RPM_STRING_ARRAY_TYPE, newEVR, k);
1033 xx = headerAddOrAppendEntry(h, requireTags[i+2], RPM_INT32_TYPE,
1036 newNames = hfd(newNames, nnt);
1037 newEVR = hfd(newEVR, nvt);
1038 Names = hfd(Names, rnt);
1044 * Mark files in database shared with this package as "replaced".
1045 * @param psm package state machine data
1048 static int markReplacedFiles(const PSM_t psm)
1049 /*@globals fileSystem@*/
1050 /*@modifies fileSystem @*/
1052 const rpmTransactionSet ts = psm->ts;
1054 HGE_t hge = (HGE_t)fi->hge;
1055 const struct sharedFileInfo * replaced = fi->replaced;
1056 const struct sharedFileInfo * sfi;
1057 rpmdbMatchIterator mi;
1059 unsigned int * offsets;
1063 if (!(fi->fc > 0 && fi->replaced))
1067 for (sfi = replaced; sfi->otherPkg; sfi++) {
1068 if (prev && prev == sfi->otherPkg)
1070 prev = sfi->otherPkg;
1076 offsets = alloca(num * sizeof(*offsets));
1078 for (sfi = replaced; sfi->otherPkg; sfi++) {
1079 if (prev && prev == sfi->otherPkg)
1081 prev = sfi->otherPkg;
1082 offsets[num++] = sfi->otherPkg;
1085 mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, NULL, 0);
1086 xx = rpmdbAppendIterator(mi, offsets, num);
1087 xx = rpmdbSetIteratorRewrite(mi, 1);
1090 while ((h = rpmdbNextIterator(mi)) != NULL) {
1097 if (!hge(h, RPMTAG_FILESTATES, NULL, (void **)&secStates, &count))
1100 prev = rpmdbGetIteratorOffset(mi);
1102 while (sfi->otherPkg && sfi->otherPkg == prev) {
1103 assert(sfi->otherFileNum < count);
1104 if (secStates[sfi->otherFileNum] != RPMFILE_STATE_REPLACED) {
1105 secStates[sfi->otherFileNum] = RPMFILE_STATE_REPLACED;
1106 if (modified == 0) {
1107 /* Modified header will be rewritten. */
1109 xx = rpmdbSetIteratorModified(mi, modified);
1116 mi = rpmdbFreeIterator(mi);
1122 * Create directory if it does not exist, make sure path is writable.
1123 * @note This will only create last component of directory path.
1124 * @param dpath directory path
1125 * @param dname directory use
1126 * @return rpmRC return code
1128 static rpmRC chkdir (const char * dpath, const char * dname)
1129 /*@globals fileSystem@*/
1130 /*@modifies fileSystem @*/
1135 if ((rc = Stat(dpath, &st)) < 0) {
1136 int ut = urlPath(dpath, NULL);
1139 case URL_IS_UNKNOWN:
1140 if (errno != ENOENT)
1145 rc = Mkdir(dpath, 0755);
1151 rpmError(RPMERR_CREATE, _("cannot create %%%s %s\n"),
1156 if ((rc = Access(dpath, W_OK))) {
1157 rpmError(RPMERR_CREATE, _("cannot write to %%%s %s\n"), dname, dpath);
1163 rpmRC rpmInstallSourcePackage(rpmTransactionSet ts,
1165 const char ** specFilePtr,
1166 rpmCallbackFunction notify, rpmCallbackData notifyData,
1167 const char ** cookie)
1169 TFI_t fi = xcalloc(sizeof(*fi), 1);
1170 const char * _sourcedir = NULL;
1171 const char * _specdir = NULL;
1172 const char * specFile = NULL;
1176 struct psm_s psmbuf;
1177 PSM_t psm = &psmbuf;
1181 alKey pkgKey = (alKey)0;
1183 /*@-mods -temptrans -assignexpose@*/
1184 ts->notify = notify;
1185 ts->notifyData = notifyData;
1186 /*@=mods =temptrans =assignexpose@*/
1188 /*@-mustmod@*/ /* LCL: segfault */
1189 rc = rpmReadPackageFile(ts, fd, "InstallSourcePackage", &h);
1191 if (!(rc == RPMRC_OK || rc == RPMRC_BADSIZE) || h == NULL) {
1194 rc = RPMRC_OK; /* XXX HACK */
1195 isSource = headerIsEntry(h, RPMTAG_SOURCEPACKAGE);
1198 rpmError(RPMERR_NOTSRPM, _("source package expected, binary found\n"));
1203 /* XXX don't bother with fd, linked directly into fi below. */
1204 (void) rpmtransAddPackage(ts, h, NULL, NULL, 0, NULL);
1206 fi->type = TR_ADDED;
1208 fi->h = alGetHeader(ts->addedPackages, pkgKey, 1);
1209 /* XXX can't happen */
1210 if (fi->h == NULL) {
1215 fi->multiLib = 0; /* MULTILIB for src.rpm's? */
1219 fi->key = alGetKey(ts->addedPackages, pkgKey);
1221 fi->relocs = alGetRelocs(ts->addedPackages, pkgKey);
1222 fi->fd = alGetFd(ts->addedPackages, pkgKey);
1225 /* XXX don't bother with fd, linked directly into fi below. */
1226 /*@i@*/ fi->fd = fd;
1230 /* XXX header arg unused. */
1231 loadFi(ts, fi, fi->h, 1);
1233 hfd = (fi->hfd ? fi->hfd : headerFreeData);
1234 h = headerFree(h, "InstallSourcePackage");
1236 (void) rpmInstallLoadMacros(fi, fi->h);
1238 memset(psm, 0, sizeof(*psm));
1240 psm->ts = rpmtsLink(ts, "InstallSourcePackage");
1246 if (hge(fi->h, RPMTAG_COOKIE, NULL, (void **) cookie, NULL))
1247 *cookie = xstrdup(*cookie);
1250 /* XXX FIXME: can't do endian neutral MD5 verification yet. */
1251 fi->fmd5s = hfd(fi->fmd5s, -1);
1253 /* XXX FIXME: don't do per-file mapping, force global flags. */
1254 fi->fmapflags = _free(fi->fmapflags);
1255 fi->mapflags = CPIO_MAP_PATH | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
1262 fi->fuids = xcalloc(sizeof(*fi->fuids), fi->fc);
1263 fi->fgids = xcalloc(sizeof(*fi->fgids), fi->fc);
1264 for (i = 0; i < fi->fc; i++) {
1265 fi->fuids[i] = fi->uid;
1266 fi->fgids[i] = fi->gid;
1269 for (i = 0; i < fi->fc; i++) {
1270 fi->actions[i] = FA_CREATE;
1275 if (fi->h != NULL) { /* XXX can't happen */
1276 rpmBuildFileList(fi->h, &fi->apath, NULL);
1278 if (headerIsEntry(fi->h, RPMTAG_COOKIE))
1279 for (i = 0; i < fi->fc; i++)
1280 if (fi->fflags[i] & RPMFILE_SPECFILE) break;
1284 /* Find the spec file by name. */
1285 for (i = 0; i < fi->fc; i++) {
1286 const char * t = fi->apath[i];
1287 t += strlen(fi->apath[i]) - 5;
1288 if (!strcmp(t, ".spec")) break;
1292 _sourcedir = rpmGenPath(ts->rootDir, "%{_sourcedir}", "");
1293 rc = chkdir(_sourcedir, "sourcedir");
1299 _specdir = rpmGenPath(ts->rootDir, "%{_specdir}", "");
1300 rc = chkdir(_specdir, "specdir");
1306 /* Build dnl/dil with {_sourcedir, _specdir} as values. */
1308 int speclen = strlen(_specdir) + 2;
1309 int sourcelen = strlen(_sourcedir) + 2;
1312 fi->dnl = hfd(fi->dnl, -1);
1315 fi->dnl = xmalloc(fi->dc * sizeof(*fi->dnl) + fi->fc * sizeof(*fi->dil) +
1316 speclen + sourcelen);
1317 fi->dil = (int *)(fi->dnl + fi->dc);
1318 memset(fi->dil, 0, fi->fc * sizeof(*fi->dil));
1320 /*@-dependenttrans@*/
1321 fi->dnl[0] = t = (char *)(fi->dil + fi->fc);
1322 fi->dnl[1] = t = stpcpy( stpcpy(t, _sourcedir), "/") + 1;
1323 /*@=dependenttrans@*/
1324 (void) stpcpy( stpcpy(t, _specdir), "/");
1326 t = xmalloc(speclen + strlen(fi->bnl[i]) + 1);
1327 (void) stpcpy( stpcpy( stpcpy(t, _specdir), "/"), fi->bnl[i]);
1330 rpmError(RPMERR_NOSPEC, _("source package contains no .spec file\n"));
1335 psm->goal = PSM_PKGINSTALL;
1337 /*@-compmempass@*/ /* FIX: psm->fi->dnl should be owned. */
1338 rc = psmStage(psm, PSM_PROCESS);
1340 (void) psmStage(psm, PSM_FINI);
1343 if (rc) rc = RPMRC_FAIL;
1346 if (specFilePtr && specFile && rc == RPMRC_OK)
1347 *specFilePtr = specFile;
1349 specFile = _free(specFile);
1351 _specdir = _free(_specdir);
1352 _sourcedir = _free(_sourcedir);
1354 if (h) h = headerFree(h, "InstallSourcePackage exit");
1358 /*@-refcounttrans@*/ /* FIX: fi needs to be only */
1360 /*@=refcounttrans@*/
1363 psm->ts = rpmtsUnlink(ts, "InstallSourcePackage");
1368 /*@observer@*/ /*@unchecked@*/
1369 static char * SCRIPT_PATH = "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin";
1372 * Return scriptlet name from tag.
1373 * @param tag scriptlet tag
1374 * @return name of scriptlet
1376 static /*@observer@*/ const char * const tag2sln(int tag)
1380 case RPMTAG_PREIN: return "%pre";
1381 case RPMTAG_POSTIN: return "%post";
1382 case RPMTAG_PREUN: return "%preun";
1383 case RPMTAG_POSTUN: return "%postun";
1384 case RPMTAG_VERIFYSCRIPT: return "%verify";
1386 return "%unknownscript";
1390 * Run scriptlet with args.
1392 * Run a script with an interpreter. If the interpreter is not specified,
1393 * /bin/sh will be used. If the interpreter is /bin/sh, then the args from
1394 * the header will be ignored, passing instead arg1 and arg2.
1396 * @param psm package state machine data
1398 * @param sln name of scriptlet section
1399 * @param progArgc no. of args from header
1400 * @param progArgv args from header, progArgv[0] is the interpreter to use
1401 * @param script scriptlet from header
1402 * @param arg1 no. instances of package installed after scriptlet exec
1404 * @param arg2 ditto, but for the target package
1405 * @return 0 on success, 1 on error
1407 static int runScript(PSM_t psm, Header h,
1409 int progArgc, const char ** progArgv,
1410 const char * script, int arg1, int arg2)
1411 /*@globals rpmGlobalMacroContext,
1412 fileSystem, internalState@*/
1413 /*@modifies psm, rpmGlobalMacroContext, fileSystem, internalState @*/
1415 const rpmTransactionSet ts = psm->ts;
1417 HGE_t hge = fi->hge;
1418 HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
1419 const char ** argv = NULL;
1421 const char ** prefixes = NULL;
1424 const char * oldPrefix;
1425 int maxPrefixLength;
1427 char * prefixBuf = NULL;
1430 const char * fn = NULL;
1432 int freePrefixes = 0;
1434 rpmRC rc = RPMRC_OK;
1435 const char *n, *v, *r;
1437 if (progArgv == NULL && script == NULL)
1440 rpmMessage(RPMMESS_DEBUG, _("%s: running %s scriptlet\n"),
1441 psm->stepName, tag2sln(psm->scriptTag));
1444 argv = alloca(5 * sizeof(*argv));
1445 argv[0] = "/bin/sh";
1448 argv = alloca((progArgc + 4) * sizeof(*argv));
1449 memcpy(argv, progArgv, progArgc * sizeof(*argv));
1453 xx = headerNVR(h, &n, &v, &r);
1454 if (hge(h, RPMTAG_INSTPREFIXES, &ipt, (void **) &prefixes, &numPrefixes)) {
1456 } else if (hge(h, RPMTAG_INSTALLPREFIX, NULL, (void **) &oldPrefix, NULL)) {
1457 prefixes = &oldPrefix;
1463 maxPrefixLength = 0;
1464 for (i = 0; i < numPrefixes; i++) {
1465 len = strlen(prefixes[i]);
1466 if (len > maxPrefixLength) maxPrefixLength = len;
1468 prefixBuf = alloca(maxPrefixLength + 50);
1473 if (makeTempFile((!ts->chrootDone ? ts->rootDir : "/"), &fn, &fd)) {
1474 if (freePrefixes) free(prefixes);
1480 (!strcmp(argv[0], "/bin/sh") || !strcmp(argv[0], "/bin/bash")))
1482 static const char set_x[] = "set -x\n";
1483 xx = Fwrite(set_x, sizeof(set_x[0]), sizeof(set_x)-1, fd);
1486 xx = Fwrite(script, sizeof(script[0]), strlen(script), fd);
1489 { const char * sn = fn;
1490 if (!ts->chrootDone &&
1491 !(ts->rootDir[0] == '/' && ts->rootDir[1] == '\0'))
1493 sn += strlen(ts->rootDir)-1;
1499 char *av = alloca(20);
1500 sprintf(av, "%d", arg1);
1504 char *av = alloca(20);
1505 sprintf(av, "%d", arg2);
1512 if (ts->scriptFd != NULL) {
1513 if (rpmIsVerbose()) {
1514 out = fdDup(Fileno(ts->scriptFd));
1516 out = Fopen("/dev/null", "w.fdio");
1518 out = fdDup(Fileno(ts->scriptFd));
1522 out = fdDup(STDOUT_FILENO);
1524 out = fdLink(out, "runScript persist");
1527 if (out == NULL) return 1; /* XXX can't happen */
1529 if (!(child = fork())) {
1530 const char * rootDir;
1533 pipes[0] = pipes[1] = 0;
1534 /* make stdin inaccessible */
1536 xx = close(pipes[1]);
1537 xx = dup2(pipes[0], STDIN_FILENO);
1538 xx = close(pipes[0]);
1541 if (ts->scriptFd != NULL) {
1542 int sfdno = Fileno(ts->scriptFd);
1543 int ofdno = Fileno(out);
1544 if (sfdno != STDERR_FILENO)
1545 xx = dup2(sfdno, STDERR_FILENO);
1546 if (ofdno != STDOUT_FILENO)
1547 xx = dup2(ofdno, STDOUT_FILENO);
1548 /* make sure we don't close stdin/stderr/stdout by mistake! */
1549 if (ofdno > STDERR_FILENO && ofdno != sfdno) {
1552 if (sfdno > STDERR_FILENO) {
1553 xx = Fclose (ts->scriptFd);
1559 { const char *ipath = rpmExpand("PATH=%{_install_script_path}", NULL);
1560 const char *path = SCRIPT_PATH;
1562 if (ipath && ipath[5] != '%')
1565 xx = doputenv(path);
1567 ipath = _free(ipath);
1572 for (i = 0; i < numPrefixes; i++) {
1573 sprintf(prefixBuf, "RPM_INSTALL_PREFIX%d=%s", i, prefixes[i]);
1574 xx = doputenv(prefixBuf);
1576 /* backwards compatibility */
1578 sprintf(prefixBuf, "RPM_INSTALL_PREFIX=%s", prefixes[i]);
1579 xx = doputenv(prefixBuf);
1583 if ((rootDir = ts->rootDir) != NULL) /* XXX can't happen */
1584 switch(urlIsURL(rootDir)) {
1586 rootDir += sizeof("file://") - 1;
1587 rootDir = strchr(rootDir, '/');
1589 case URL_IS_UNKNOWN:
1590 if (!ts->chrootDone && !(rootDir[0] == '/' && rootDir[1] == '\0')) {
1591 /*@-superuser -noeffect @*/
1592 xx = chroot(rootDir);
1593 /*@=superuser =noeffect @*/
1596 xx = execv(argv[0], (char *const *)argv);
1606 if (waitpid(child, &status, 0) < 0) {
1607 rpmError(RPMERR_SCRIPT,
1608 _("execution of %s scriptlet from %s-%s-%s failed, waitpid returned %s\n"),
1609 sln, n, v, r, strerror (errno));
1610 /* XXX what to do here? */
1613 if (!WIFEXITED(status) || WEXITSTATUS(status)) {
1614 rpmError(RPMERR_SCRIPT,
1615 _("execution of %s scriptlet from %s-%s-%s failed, exit status %d\n"),
1616 sln, n, v, r, WEXITSTATUS(status));
1621 if (freePrefixes) prefixes = hfd(prefixes, ipt);
1623 xx = Fclose(out); /* XXX dup'd STDOUT_FILENO */
1637 * Retrieve and run scriptlet from header.
1638 * @param psm package state machine data
1639 * @return rpmRC return code
1641 static rpmRC runInstScript(PSM_t psm)
1642 /*@globals rpmGlobalMacroContext,
1643 fileSystem, internalState @*/
1644 /*@modifies psm, rpmGlobalMacroContext,
1645 fileSystem, internalState @*/
1648 HGE_t hge = fi->hge;
1649 HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
1653 rpmTagType ptt, stt;
1654 const char * script;
1655 rpmRC rc = RPMRC_OK;
1659 * headerGetEntry() sets the data pointer to NULL if the entry does
1662 xx = hge(fi->h, psm->scriptTag, &stt, (void **) &script, NULL);
1663 xx = hge(fi->h, psm->progTag, &ptt, (void **) &progArgv, &progArgc);
1664 if (progArgv == NULL && script == NULL)
1668 if (progArgv && ptt == RPM_STRING_TYPE) {
1669 argv = alloca(sizeof(*argv));
1670 *argv = (const char *) progArgv;
1672 argv = (const char **) progArgv;
1676 if (fi->h != NULL) /* XXX can't happen */
1677 rc = runScript(psm, fi->h, tag2sln(psm->scriptTag), progArgc, argv,
1678 script, psm->scriptArg, -1);
1681 progArgv = hfd(progArgv, ptt);
1682 script = hfd(script, stt);
1687 * @param psm package state machine data
1691 * @param triggersAlreadyRun
1694 static int handleOneTrigger(PSM_t psm, Header sourceH, Header triggeredH,
1695 int arg2, unsigned char * triggersAlreadyRun)
1696 /*@globals rpmGlobalMacroContext,
1697 fileSystem, internalState@*/
1698 /*@modifies psm, triggeredH, *triggersAlreadyRun, rpmGlobalMacroContext,
1699 fileSystem, internalState @*/
1702 const rpmTransactionSet ts = psm->ts;
1704 HGE_t hge = fi->hge;
1705 HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
1706 rpmDepSet trigger = NULL;
1707 const char ** triggerScripts;
1708 const char ** triggerProgs;
1709 int_32 * triggerIndices;
1710 const char * sourceName;
1711 rpmRC rc = RPMRC_OK;
1714 xx = headerNVR(sourceH, &sourceName, NULL, NULL);
1716 trigger = dsiInit(dsNew(triggeredH, RPMTAG_TRIGGERNAME, scareMem));
1717 if (trigger != NULL)
1718 while (dsiNext(trigger) >= 0) {
1719 rpmTagType tit, tst, tpt;
1721 int_32 Flags = dsiGetFlags(trigger);
1726 if ((Name = dsiGetN(trigger)) == NULL)
1727 continue; /* XXX can't happen */
1729 if (strcmp(Name, sourceName))
1731 if (!(Flags & psm->sense))
1736 * For some reason, the TRIGGERVERSION stuff includes the name of
1737 * the package which the trigger is based on. We need to skip
1738 * over that here. I suspect that we'll change our minds on this
1739 * and remove that, so I'm going to just 'do the right thing'.
1741 skip = strlen(Name);
1742 if (!strncmp(trigger->EVR[trigger->i], trigger->N[trigger->i], skip) &&
1743 (trigger->EVR[trigger->i][skip] == '-'))
1749 if (!headerMatchesDepFlags(sourceH, trigger))
1752 if (!( hge(triggeredH, RPMTAG_TRIGGERINDEX, &tit,
1753 (void **) &triggerIndices, NULL) &&
1754 hge(triggeredH, RPMTAG_TRIGGERSCRIPTS, &tst,
1755 (void **) &triggerScripts, NULL) &&
1756 hge(triggeredH, RPMTAG_TRIGGERSCRIPTPROG, &tpt,
1757 (void **) &triggerProgs, NULL))
1764 arg1 = rpmdbCountPackages(ts->rpmdb, Name);
1766 /* XXX W2DO? fails as "execution of script failed" */
1769 arg1 += psm->countCorrection;
1770 index = triggerIndices[trigger->i];
1771 if (triggersAlreadyRun == NULL ||
1772 triggersAlreadyRun[index] == 0)
1774 rc = runScript(psm, triggeredH, "%trigger", 1,
1775 triggerProgs + index, triggerScripts[index],
1777 if (triggersAlreadyRun != NULL)
1778 triggersAlreadyRun[index] = 1;
1783 triggerIndices = hfd(triggerIndices, tit);
1784 triggerScripts = hfd(triggerScripts, tst);
1785 triggerProgs = hfd(triggerProgs, tpt);
1788 * Each target/source header pair can only result in a single
1794 trigger = dsFree(trigger);
1800 * Run trigger scripts in the database that are fired by this header.
1801 * @param psm package state machine data
1802 * @return 0 on success, 1 on error
1804 static int runTriggers(PSM_t psm)
1805 /*@globals rpmGlobalMacroContext,
1806 fileSystem, internalState @*/
1807 /*@modifies psm, rpmGlobalMacroContext,
1808 fileSystem, internalState @*/
1810 const rpmTransactionSet ts = psm->ts;
1813 rpmRC rc = RPMRC_OK;
1815 numPackage = rpmdbCountPackages(ts->rpmdb, fi->name) + psm->countCorrection;
1819 if (fi->h != NULL) /* XXX can't happen */
1820 { Header triggeredH;
1821 rpmdbMatchIterator mi;
1822 int countCorrection = psm->countCorrection;
1824 psm->countCorrection = 0;
1825 mi = rpmtsInitIterator(ts, RPMTAG_TRIGGERNAME, fi->name, 0);
1826 while((triggeredH = rpmdbNextIterator(mi)) != NULL) {
1827 rc |= handleOneTrigger(psm, fi->h, triggeredH, numPackage, NULL);
1830 mi = rpmdbFreeIterator(mi);
1831 psm->countCorrection = countCorrection;
1838 * Run triggers from this header that are fired by headers in the database.
1839 * @param psm package state machine data
1840 * @return 0 on success, 1 on error
1842 static int runImmedTriggers(PSM_t psm)
1843 /*@globals rpmGlobalMacroContext,
1844 fileSystem, internalState @*/
1845 /*@modifies psm, rpmGlobalMacroContext,
1846 fileSystem, internalState @*/
1848 const rpmTransactionSet ts = psm->ts;
1850 HGE_t hge = fi->hge;
1851 HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
1852 const char ** triggerNames;
1854 int_32 * triggerIndices;
1855 rpmTagType tnt, tit;
1856 int numTriggerIndices;
1857 unsigned char * triggersRun;
1858 rpmRC rc = RPMRC_OK;
1860 if (fi->h == NULL) return 0; /* XXX can't happen */
1862 if (!( hge(fi->h, RPMTAG_TRIGGERNAME, &tnt,
1863 (void **) &triggerNames, &numTriggers) &&
1864 hge(fi->h, RPMTAG_TRIGGERINDEX, &tit,
1865 (void **) &triggerIndices, &numTriggerIndices))
1869 triggersRun = alloca(sizeof(*triggersRun) * numTriggerIndices);
1870 memset(triggersRun, 0, sizeof(*triggersRun) * numTriggerIndices);
1872 { Header sourceH = NULL;
1875 for (i = 0; i < numTriggers; i++) {
1876 rpmdbMatchIterator mi;
1878 if (triggersRun[triggerIndices[i]] != 0) continue;
1880 mi = rpmtsInitIterator(ts, RPMTAG_NAME, triggerNames[i], 0);
1882 while((sourceH = rpmdbNextIterator(mi)) != NULL) {
1883 rc |= handleOneTrigger(psm, sourceH, fi->h,
1884 rpmdbGetIteratorCount(mi),
1888 mi = rpmdbFreeIterator(mi);
1891 triggerIndices = hfd(triggerIndices, tit);
1892 triggerNames = hfd(triggerNames, tnt);
1896 /*@observer@*/ static const char *const pkgStageString(pkgStage a)
1900 case PSM_UNKNOWN: return "unknown";
1902 case PSM_PKGINSTALL: return " install";
1903 case PSM_PKGERASE: return " erase";
1904 case PSM_PKGCOMMIT: return " commit";
1905 case PSM_PKGSAVE: return "repackage";
1907 case PSM_INIT: return "init";
1908 case PSM_PRE: return "pre";
1909 case PSM_PROCESS: return "process";
1910 case PSM_POST: return "post";
1911 case PSM_UNDO: return "undo";
1912 case PSM_FINI: return "fini";
1914 case PSM_CREATE: return "create";
1915 case PSM_NOTIFY: return "notify";
1916 case PSM_DESTROY: return "destroy";
1917 case PSM_COMMIT: return "commit";
1919 case PSM_CHROOT_IN: return "chrootin";
1920 case PSM_CHROOT_OUT: return "chrootout";
1921 case PSM_SCRIPT: return "script";
1922 case PSM_TRIGGERS: return "triggers";
1923 case PSM_IMMED_TRIGGERS: return "immedtriggers";
1925 case PSM_RPMIO_FLAGS: return "rpmioflags";
1927 case PSM_RPMDB_LOAD: return "rpmdbload";
1928 case PSM_RPMDB_ADD: return "rpmdbadd";
1929 case PSM_RPMDB_REMOVE: return "rpmdbremove";
1931 default: return "???";
1937 * @todo Packages w/o files never get a callback, hence don't get displayed
1938 * on install with -v.
1940 /*@-nullpass@*/ /* FIX: testing null annotation for fi->h */
1941 int psmStage(PSM_t psm, pkgStage stage)
1943 const rpmTransactionSet ts = psm->ts;
1945 HGE_t hge = fi->hge;
1946 HME_t hme = fi->hme;
1947 HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
1957 rpmMessage(RPMMESS_DEBUG, _("%s: %s-%s-%s has %d files, test = %d\n"),
1958 psm->stepName, fi->name, fi->version, fi->release,
1959 fi->fc, (ts->transFlags & RPMTRANS_FLAG_TEST));
1962 * When we run scripts, we pass an argument which is the number of
1963 * versions of this package that will be installed when we are
1966 psm->npkgs_installed = rpmdbCountPackages(ts->rpmdb, fi->name);
1967 if (psm->npkgs_installed < 0) {
1972 if (psm->goal == PSM_PKGINSTALL) {
1973 psm->scriptArg = psm->npkgs_installed + 1;
1975 assert(psm->mi == NULL);
1976 psm->mi = rpmtsInitIterator(ts, RPMTAG_NAME, fi->name, 0);
1977 xx = rpmdbSetIteratorRE(psm->mi, RPMTAG_VERSION,
1978 RPMMIRE_DEFAULT, fi->version);
1979 xx = rpmdbSetIteratorRE(psm->mi, RPMTAG_RELEASE,
1980 RPMMIRE_DEFAULT, fi->release);
1982 while ((psm->oh = rpmdbNextIterator(psm->mi))) {
1983 fi->record = rpmdbGetIteratorOffset(psm->mi);
1984 if (ts->transFlags & RPMTRANS_FLAG_MULTILIB)
1985 psm->oh = headerCopy(psm->oh);
1988 /*@loopbreak@*/ break;
1990 psm->mi = rpmdbFreeIterator(psm->mi);
1993 if (fi->fc > 0 && fi->fstates == NULL) {
1994 fi->fstates = xmalloc(sizeof(*fi->fstates) * fi->fc);
1995 memset(fi->fstates, RPMFILE_STATE_NORMAL, fi->fc);
1998 if (fi->fc <= 0) break;
1999 if (ts->transFlags & RPMTRANS_FLAG_JUSTDB) break;
2002 * Old format relocateable packages need the entire default
2003 * prefix stripped to form the cpio list, while all other packages
2004 * need the leading / stripped.
2007 rc = hge(fi->h, RPMTAG_DEFAULTPREFIX, NULL, (void **) &p, NULL);
2008 fi->striplen = (rc ? strlen(p) + 1 : 1);
2011 CPIO_MAP_PATH | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
2013 if (headerIsEntry(fi->h, RPMTAG_ORIGBASENAMES))
2014 buildOrigFileList(fi->h, &fi->apath, NULL);
2016 rpmBuildFileList(fi->h, &fi->apath, NULL);
2018 if (fi->fuser == NULL)
2019 xx = hge(fi->h, RPMTAG_FILEUSERNAME, NULL,
2020 (void **) &fi->fuser, NULL);
2021 if (fi->fgroup == NULL)
2022 xx = hge(fi->h, RPMTAG_FILEGROUPNAME, NULL,
2023 (void **) &fi->fgroup, NULL);
2024 if (fi->fuids == NULL)
2025 fi->fuids = xcalloc(sizeof(*fi->fuids), fi->fc);
2026 if (fi->fgids == NULL)
2027 fi->fgids = xcalloc(sizeof(*fi->fgids), fi->fc);
2030 if (psm->goal == PSM_PKGERASE || psm->goal == PSM_PKGSAVE) {
2031 psm->scriptArg = psm->npkgs_installed - 1;
2033 /* Retrieve installed header. */
2034 rc = psmStage(psm, PSM_RPMDB_LOAD);
2036 if (psm->goal == PSM_PKGSAVE) {
2037 /* Open output package for writing. */
2038 { const char * bfmt = rpmGetPath("%{_repackage_name_fmt}", NULL);
2039 const char * pkgbn =
2040 headerSprintf(fi->h, bfmt, rpmTagTable, rpmHeaderFormats, NULL);
2043 psm->pkgURL = rpmGenPath("%{?_repackage_root:%{_repackage_root}}",
2044 "%{?_repackage_dir:%{_repackage_dir}}",
2046 pkgbn = _free(pkgbn);
2047 (void) urlPath(psm->pkgURL, &psm->pkgfn);
2048 psm->fd = Fopen(psm->pkgfn, "w.ufdio");
2049 if (psm->fd == NULL || Ferror(psm->fd)) {
2057 if (ts->transFlags & RPMTRANS_FLAG_TEST) break;
2059 /* Change root directory if requested and not already done. */
2060 rc = psmStage(psm, PSM_CHROOT_IN);
2062 if (psm->goal == PSM_PKGINSTALL) {
2063 psm->scriptTag = RPMTAG_PREIN;
2064 psm->progTag = RPMTAG_PREINPROG;
2066 if (!(ts->transFlags & RPMTRANS_FLAG_NOTRIGGERPREIN)) {
2067 /* XXX FIXME: implement %triggerprein. */
2070 if (!(ts->transFlags & RPMTRANS_FLAG_NOPRE)) {
2071 rc = psmStage(psm, PSM_SCRIPT);
2073 rpmError(RPMERR_SCRIPT,
2074 _("%s: %s scriptlet failed (%d), skipping %s-%s-%s\n"),
2075 psm->stepName, tag2sln(psm->scriptTag), rc,
2076 fi->name, fi->version, fi->release);
2082 if (psm->goal == PSM_PKGERASE) {
2083 psm->scriptTag = RPMTAG_PREUN;
2084 psm->progTag = RPMTAG_PREUNPROG;
2085 psm->sense = RPMSENSE_TRIGGERUN;
2086 psm->countCorrection = -1;
2088 if (!(ts->transFlags & RPMTRANS_FLAG_NOTRIGGERUN)) {
2089 /* Run triggers in other package(s) this package sets off. */
2090 rc = psmStage(psm, PSM_TRIGGERS);
2093 /* Run triggers in this package other package(s) set off. */
2094 rc = psmStage(psm, PSM_IMMED_TRIGGERS);
2098 if (!(ts->transFlags & RPMTRANS_FLAG_NOPREUN))
2099 rc = psmStage(psm, PSM_SCRIPT);
2101 if (psm->goal == PSM_PKGSAVE) {
2102 /* Regenerate original header. */
2106 if (headerGetEntry(fi->h, RPMTAG_HEADERIMMUTABLE, &uht, &uh, &uhc)) {
2107 psm->oh = headerCopyLoad(uh);
2110 psm->oh = headerLink(fi->h, "PSM_PKGSAVE_PRE)");
2114 /* Add remove transaction id to header. */
2116 { int_32 tid = ts->id;
2117 xx = headerAddEntry(psm->oh, RPMTAG_REMOVETID,
2118 RPM_INT32_TYPE, &tid, 1);
2121 /* Retrieve type of payload compression. */
2122 /*@-nullstate@*/ /* FIX: psm->oh may be NULL */
2123 rc = psmStage(psm, PSM_RPMIO_FLAGS);
2126 /* Write the lead section into the package. */
2129 struct rpmlead lead;
2132 rpmGetArchInfo(NULL, &archnum);
2133 rpmGetOsInfo(NULL, &osnum);
2136 memset(&lead, 0, sizeof(lead));
2137 /* XXX Set package version conditioned on noDirTokens. */
2140 lead.type = RPMLEAD_BINARY;
2141 lead.archnum = archnum;
2143 lead.signature_type = RPMSIGTYPE_HEADERSIG;
2146 sprintf(buf, "%s-%s-%s", fi->name, fi->version, fi->release);
2147 strncpy(lead.name, buf, sizeof(lead.name));
2150 rc = writeLead(psm->fd, &lead);
2152 rpmError(RPMERR_NOSPACE, _("Unable to write package: %s\n"),
2153 Fstrerror(psm->fd));
2159 /* Write the signature section into the package. */
2160 { Header sig = headerRegenSigHeader(fi->h);
2161 rc = rpmWriteSignature(psm->fd, sig);
2162 sig = rpmFreeSignature(sig);
2166 /* Write the metadata section into the package. */
2167 rc = headerWrite(psm->fd, psm->oh, HEADER_MAGIC_YES);
2172 if (ts->transFlags & RPMTRANS_FLAG_TEST) break;
2174 if (psm->goal == PSM_PKGINSTALL) {
2177 if (fi->fc <= 0) break;
2178 if (ts->transFlags & RPMTRANS_FLAG_JUSTDB) break;
2180 for (i = 0; i < fi->fc; i++) {
2186 if (fi->fuser && unameToUid(fi->fuser[i], &uid)) {
2187 rpmMessage(RPMMESS_WARNING,
2188 _("user %s does not exist - using root\n"),
2191 /* XXX this diddles header memory. */
2192 fi->fmodes[i] &= ~S_ISUID; /* turn off the suid bit */
2195 if (fi->fgroup && gnameToGid(fi->fgroup[i], &gid)) {
2196 rpmMessage(RPMMESS_WARNING,
2197 _("group %s does not exist - using root\n"),
2200 /* XXX this diddles header memory. */
2201 fi->fmodes[i] &= ~S_ISGID; /* turn off the sgid bit */
2203 if (fi->fuids) fi->fuids[i] = uid;
2204 if (fi->fgids) fi->fgids[i] = gid;
2207 /* Retrieve type of payload compression. */
2208 rc = psmStage(psm, PSM_RPMIO_FLAGS);
2210 if (fi->fd == NULL) { /* XXX can't happen */
2214 /*@-nullpass@*/ /* LCL: fi->fd != NULL here. */
2215 psm->cfd = Fdopen(fdDup(Fileno(fi->fd)), psm->rpmio_flags);
2217 if (psm->cfd == NULL) { /* XXX can't happen */
2222 rc = fsmSetup(fi->fsm, FSM_PKGINSTALL, ts, fi,
2223 psm->cfd, NULL, &psm->failedFile);
2224 xx = fsmTeardown(fi->fsm);
2226 saveerrno = errno; /* XXX FIXME: Fclose with libio destroys errno */
2227 xx = Fclose(psm->cfd);
2230 errno = saveerrno; /* XXX FIXME: Fclose with libio destroys errno */
2234 rc = psmStage(psm, PSM_COMMIT);
2237 rpmError(RPMERR_CPIO,
2238 _("unpacking of archive failed%s%s: %s\n"),
2239 (psm->failedFile != NULL ? _(" on file ") : ""),
2240 (psm->failedFile != NULL ? psm->failedFile : ""),
2245 psm->what = RPMCALLBACK_INST_PROGRESS;
2246 psm->amount = (fi->archiveSize ? fi->archiveSize : 100);
2247 psm->total = psm->amount;
2248 xx = psmStage(psm, PSM_NOTIFY);
2250 if (psm->goal == PSM_PKGERASE) {
2252 if (fi->fc <= 0) break;
2253 if (ts->transFlags & RPMTRANS_FLAG_JUSTDB) break;
2254 if (ts->transFlags & RPMTRANS_FLAG_APPLYONLY) break;
2256 psm->what = RPMCALLBACK_UNINST_START;
2257 psm->amount = fi->fc; /* XXX W2DO? looks wrong. */
2258 psm->total = fi->fc;
2259 xx = psmStage(psm, PSM_NOTIFY);
2261 rc = fsmSetup(fi->fsm, FSM_PKGERASE, ts, fi,
2262 NULL, NULL, &psm->failedFile);
2263 xx = fsmTeardown(fi->fsm);
2265 psm->what = RPMCALLBACK_UNINST_STOP;
2266 psm->amount = 0; /* XXX W2DO? looks wrong. */
2267 psm->total = fi->fc;
2268 xx = psmStage(psm, PSM_NOTIFY);
2271 if (psm->goal == PSM_PKGSAVE) {
2272 fileAction * actions = fi->actions;
2273 fileAction action = fi->action;
2275 fi->action = FA_COPYOUT;
2278 if (psm->fd == NULL) { /* XXX can't happen */
2282 /*@-nullpass@*/ /* LCL: psm->fd != NULL here. */
2283 xx = Fflush(psm->fd);
2284 psm->cfd = Fdopen(fdDup(Fileno(psm->fd)), psm->rpmio_flags);
2286 if (psm->cfd == NULL) { /* XXX can't happen */
2291 rc = fsmSetup(fi->fsm, FSM_PKGBUILD, ts, fi, psm->cfd,
2292 NULL, &psm->failedFile);
2293 xx = fsmTeardown(fi->fsm);
2295 saveerrno = errno; /* XXX FIXME: Fclose with libio destroys errno */
2296 xx = Fclose(psm->cfd);
2302 fi->action = action;
2303 fi->actions = actions;
2307 if (ts->transFlags & RPMTRANS_FLAG_TEST) break;
2309 if (psm->goal == PSM_PKGINSTALL) {
2310 int_32 installTime = (int_32) time(NULL);
2312 if (fi->h == NULL) break; /* XXX can't happen */
2313 if (fi->fstates != NULL && fi->fc > 0)
2314 xx = headerAddEntry(fi->h, RPMTAG_FILESTATES, RPM_CHAR_TYPE,
2315 fi->fstates, fi->fc);
2317 xx = headerAddEntry(fi->h, RPMTAG_INSTALLTIME, RPM_INT32_TYPE,
2320 if (ts->transFlags & RPMTRANS_FLAG_MULTILIB) {
2321 uint_32 multiLib, * newMultiLib, * p;
2323 if (hge(fi->h, RPMTAG_MULTILIBS, NULL,
2324 (void **) &newMultiLib, NULL) &&
2325 hge(psm->oh, RPMTAG_MULTILIBS, NULL,
2326 (void **) &p, NULL))
2329 multiLib |= *newMultiLib;
2330 xx = hme(psm->oh, RPMTAG_MULTILIBS, RPM_INT32_TYPE,
2333 rc = mergeFiles(fi, psm->oh, fi->h);
2339 * If this package has already been installed, remove it from
2340 * the database before adding the new one.
2342 if (fi->record && !(ts->transFlags & RPMTRANS_FLAG_APPLYONLY)) {
2343 rc = psmStage(psm, PSM_RPMDB_REMOVE);
2347 rc = psmStage(psm, PSM_RPMDB_ADD);
2350 psm->scriptTag = RPMTAG_POSTIN;
2351 psm->progTag = RPMTAG_POSTINPROG;
2352 psm->sense = RPMSENSE_TRIGGERIN;
2353 psm->countCorrection = 0;
2355 if (!(ts->transFlags & RPMTRANS_FLAG_NOPOST)) {
2356 rc = psmStage(psm, PSM_SCRIPT);
2359 if (!(ts->transFlags & RPMTRANS_FLAG_NOTRIGGERIN)) {
2360 /* Run triggers in other package(s) this package sets off. */
2361 rc = psmStage(psm, PSM_TRIGGERS);
2364 /* Run triggers in this package other package(s) set off. */
2365 rc = psmStage(psm, PSM_IMMED_TRIGGERS);
2369 if (!(ts->transFlags & RPMTRANS_FLAG_APPLYONLY))
2370 rc = markReplacedFiles(psm);
2373 if (psm->goal == PSM_PKGERASE) {
2375 psm->scriptTag = RPMTAG_POSTUN;
2376 psm->progTag = RPMTAG_POSTUNPROG;
2377 psm->sense = RPMSENSE_TRIGGERPOSTUN;
2378 psm->countCorrection = -1;
2380 if (!(ts->transFlags & RPMTRANS_FLAG_NOPOSTUN)) {
2381 rc = psmStage(psm, PSM_SCRIPT);
2382 /* XXX WTFO? postun failures don't cause erasure failure. */
2385 if (!(ts->transFlags & RPMTRANS_FLAG_NOTRIGGERPOSTUN)) {
2386 /* Run triggers in other package(s) this package sets off. */
2387 rc = psmStage(psm, PSM_TRIGGERS);
2391 if (!(ts->transFlags & RPMTRANS_FLAG_APPLYONLY))
2392 rc = psmStage(psm, PSM_RPMDB_REMOVE);
2394 if (psm->goal == PSM_PKGSAVE) {
2397 /* Restore root directory if changed. */
2398 xx = psmStage(psm, PSM_CHROOT_OUT);
2403 /* Restore root directory if changed. */
2404 xx = psmStage(psm, PSM_CHROOT_OUT);
2407 saveerrno = errno; /* XXX FIXME: Fclose with libio destroys errno */
2408 xx = Fclose(psm->fd);
2415 if (psm->goal == PSM_PKGSAVE) {
2417 rpmMessage(RPMMESS_VERBOSE, _("Wrote: %s\n"),
2418 (psm->pkgURL ? psm->pkgURL : "???"));
2423 if (psm->failedFile)
2424 rpmError(RPMERR_CPIO,
2425 _("%s failed on file %s: %s\n"),
2426 psm->stepName, psm->failedFile, cpioStrerror(rc));
2428 rpmError(RPMERR_CPIO, _("%s failed: %s\n"),
2429 psm->stepName, cpioStrerror(rc));
2432 if (fi->h && (psm->goal == PSM_PKGERASE || psm->goal == PSM_PKGSAVE))
2433 fi->h = headerFree(fi->h, "PSM_PKGSAVE_POST fi->h");
2434 psm->oh = headerFree(psm->oh, "PSM_PKGSAVE_POST psm->oh");
2435 psm->pkgURL = _free(psm->pkgURL);
2436 psm->rpmio_flags = _free(psm->rpmio_flags);
2437 psm->failedFile = _free(psm->failedFile);
2439 fi->fgids = _free(fi->fgids);
2440 fi->fuids = _free(fi->fuids);
2441 fi->fgroup = hfd(fi->fgroup, -1);
2442 fi->fuser = hfd(fi->fuser, -1);
2443 fi->apath = _free(fi->apath);
2444 fi->fstates = _free(fi->fstates);
2447 case PSM_PKGINSTALL:
2452 psm->stepName = pkgStageString(stage);
2454 rc = psmStage(psm, PSM_INIT);
2455 if (!rc) rc = psmStage(psm, PSM_PRE);
2456 if (!rc) rc = psmStage(psm, PSM_PROCESS);
2457 if (!rc) rc = psmStage(psm, PSM_POST);
2458 xx = psmStage(psm, PSM_FINI);
2466 if (ts && ts->notify) {
2467 /*@-noeffectuncon @*/ /* FIX: check rc */
2468 (void) ts->notify(fi->h, psm->what, psm->amount, psm->total,
2469 fi->key, ts->notifyData);
2470 /*@=noeffectuncon @*/
2476 if (!(ts->transFlags & RPMTRANS_FLAG_PKGCOMMIT)) break;
2477 if (ts->transFlags & RPMTRANS_FLAG_APPLYONLY) break;
2479 rc = fsmSetup(fi->fsm, FSM_PKGCOMMIT, ts, fi,
2480 NULL, NULL, &psm->failedFile);
2481 xx = fsmTeardown(fi->fsm);
2485 /* Change root directory if requested and not already done. */
2486 if (ts->rootDir && !ts->chrootDone && !psm->chrootDone) {
2487 static int _loaded = 0;
2490 * This loads all of the name services libraries, in case we
2491 * don't have access to them in the chroot().
2494 (void)getpwnam("root");
2501 rc = chroot(ts->rootDir);
2503 psm->chrootDone = ts->chrootDone = 1;
2504 if (ts->rpmdb != NULL) ts->rpmdb->db_chrootDone = 1;
2507 chroot_prefix = ts->rootDir;
2512 case PSM_CHROOT_OUT:
2513 /* Restore root directory if changed. */
2514 if (psm->chrootDone) {
2518 psm->chrootDone = ts->chrootDone = 0;
2519 if (ts->rpmdb != NULL) ts->rpmdb->db_chrootDone = 0;
2521 chroot_prefix = NULL;
2523 xx = chdir(ts->currDir);
2526 case PSM_SCRIPT: /* Run current package scriptlets. */
2527 rc = runInstScript(psm);
2530 /* Run triggers in other package(s) this package sets off. */
2531 rc = runTriggers(psm);
2533 case PSM_IMMED_TRIGGERS:
2534 /* Run triggers in this package other package(s) set off. */
2535 rc = runImmedTriggers(psm);
2538 case PSM_RPMIO_FLAGS:
2539 { const char * payload_compressor = NULL;
2542 if (!hge(fi->h, RPMTAG_PAYLOADCOMPRESSOR, NULL,
2543 (void **) &payload_compressor, NULL))
2544 payload_compressor = "gzip";
2545 psm->rpmio_flags = t = xmalloc(sizeof("w9.gzdio"));
2547 t = stpcpy(t, ((psm->goal == PSM_PKGSAVE) ? "w9" : "r"));
2548 if (!strcmp(payload_compressor, "gzip"))
2549 t = stpcpy(t, ".gzdio");
2550 if (!strcmp(payload_compressor, "bzip2"))
2551 t = stpcpy(t, ".bzdio");
2555 case PSM_RPMDB_LOAD:
2556 assert(psm->mi == NULL);
2557 psm->mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES,
2558 &fi->record, sizeof(fi->record));
2560 fi->h = rpmdbNextIterator(psm->mi);
2562 fi->h = headerLink(fi->h, "PSM_RPMDB_LOAD)");
2564 fprintf(stderr, "*** PSM_RDB_LOAD: header #%u not found\n", fi->record);
2566 psm->mi = rpmdbFreeIterator(psm->mi);
2567 rc = (fi->h ? RPMRC_OK : RPMRC_FAIL);
2570 if (ts->transFlags & RPMTRANS_FLAG_TEST) break;
2571 if (fi->h != NULL) /* XXX can't happen */
2572 rc = rpmdbAdd(ts->rpmdb, ts->id, fi->h);
2574 case PSM_RPMDB_REMOVE:
2575 if (ts->transFlags & RPMTRANS_FLAG_TEST) break;
2576 rc = rpmdbRemove(ts->rpmdb, ts->id, fi->record);
2584 /*@-nullstate@*/ /* FIX: psm->oh and psm->fi->h may be NULL. */