1 /** \ingroup rpmts payload
3 * Package state machine to handle a package from a transaction set.
10 #include <rpm/rpmlib.h> /* rpmvercmp and others */
11 #include <rpm/rpmmacro.h>
12 #include <rpm/rpmds.h>
13 #include <rpm/rpmts.h>
14 #include <rpm/rpmfileutil.h>
15 #include <rpm/rpmdb.h>
16 #include <rpm/rpmlog.h>
17 #include <rpm/rpmstring.h>
21 #include "lib/fsm.h" /* XXX CPIO_FOO/FSM_FOO constants */
22 #include "lib/rpmchroot.h"
23 #include "lib/rpmfi_internal.h" /* XXX replaced/states... */
24 #include "lib/rpmte_internal.h" /* XXX internal apis */
25 #include "lib/rpmdb_internal.h" /* rpmdbAdd/Remove */
26 #include "lib/rpmts_internal.h" /* ts->plugins */
27 #include "lib/rpmscript.h"
29 #include "lib/rpmplugins.h"
33 typedef enum pkgStage_e {
47 PSM_IMMED_TRIGGERS = 55,
55 rpmts ts; /*!< transaction set */
56 rpmte te; /*!< current transaction element */
57 rpmfi fi; /*!< transaction element file info */
58 const char * goalName;
60 rpmTagVal scriptTag; /*!< Scriptlet data tag. */
61 int npkgs_installed; /*!< No. of installed instances. */
62 int scriptArg; /*!< Scriptlet package arg. */
63 rpmsenseFlags sense; /*!< One of RPMSENSE_TRIGGER{PREIN,IN,UN,POSTUN}. */
64 int countCorrection; /*!< 0 if installing, -1 if removing. */
65 rpmCallbackType what; /*!< Callback type. */
66 rpm_loff_t amount; /*!< Callback amount. */
67 rpm_loff_t total; /*!< Callback total. */
69 pkgStage stage; /*!< Current psm stage. */
70 pkgStage nstage; /*!< Next psm stage. */
72 int nrefs; /*!< Reference count. */
75 static rpmpsm rpmpsmNew(rpmts ts, rpmte te);
76 static rpmpsm rpmpsmFree(rpmpsm psm);
77 static rpmRC rpmpsmStage(rpmpsm psm, pkgStage stage);
80 * Macros to be defined from per-header tag values.
81 * @todo Should other macros be added from header when installing a package?
83 static struct tagMacro {
84 const char *macroname; /*!< Macro name to define. */
85 rpmTag tag; /*!< Header tag to use for value. */
86 } const tagMacros[] = {
87 { "name", RPMTAG_NAME },
88 { "version", RPMTAG_VERSION },
89 { "release", RPMTAG_RELEASE },
90 { "epoch", RPMTAG_EPOCH },
95 * Define per-header macros.
99 static void rpmInstallLoadMacros(Header h)
101 const struct tagMacro * tagm;
103 for (tagm = tagMacros; tagm->macroname != NULL; tagm++) {
106 if (!headerGet(h, tagm->tag, &td, HEADERGET_DEFAULT))
109 switch (rpmtdType(&td)) {
111 body = rpmtdFormat(&td, RPMTD_FORMAT_STRING, NULL);
112 addMacro(NULL, tagm->macroname, NULL, body, -1);
123 * Adjust file states in database for files shared with this package:
124 * currently either "replaced" or "wrong color".
125 * @param psm package state machine data
128 static rpmRC markReplacedFiles(const rpmpsm psm)
130 const rpmts ts = psm->ts;
131 rpmfs fs = rpmteGetFileStates(psm->te);
132 sharedFileInfo replaced = rpmfsGetReplaced(fs);
134 rpmdbMatchIterator mi;
144 for (sfi = replaced; sfi; sfi=rpmfsNextReplaced(fs, sfi)) {
145 if (prev && prev == sfi->otherPkg)
147 prev = sfi->otherPkg;
153 offsets = xmalloc(num * sizeof(*offsets));
156 for (sfi = replaced; sfi; sfi=rpmfsNextReplaced(fs, sfi)) {
157 if (prev && prev == sfi->otherPkg)
159 prev = sfi->otherPkg;
160 offsets[num++] = sfi->otherPkg;
163 mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, NULL, 0);
164 rpmdbAppendIterator(mi, offsets, num);
165 rpmdbSetIteratorRewrite(mi, 1);
168 while ((h = rpmdbNextIterator(mi)) != NULL) {
170 struct rpmtd_s secStates;
173 if (!headerGet(h, RPMTAG_FILESTATES, &secStates, HEADERGET_MINMEM))
176 prev = rpmdbGetIteratorOffset(mi);
178 while (sfi && sfi->otherPkg == prev) {
179 int ix = rpmtdSetIndex(&secStates, sfi->otherFileNum);
182 char *state = rpmtdGetChar(&secStates);
183 if (state && *state != sfi->rstate) {
184 *state = sfi->rstate;
186 /* Modified header will be rewritten. */
188 rpmdbSetIteratorModified(mi, modified);
192 sfi=rpmfsNextReplaced(fs, sfi);
194 rpmtdFreeData(&secStates);
196 rpmdbFreeIterator(mi);
202 static int rpmlibDeps(Header h)
204 rpmds req = rpmdsInit(rpmdsNew(h, RPMTAG_REQUIRENAME, 0));
206 rpmdsRpmlib(&rpmlib, NULL);
209 while (rpmdsNext(req) >= 0) {
210 if (!(rpmdsFlags(req) & RPMSENSE_RPMLIB))
212 if (rpmdsSearch(rpmlib, req) < 0) {
214 nvr = headerGetAsString(h, RPMTAG_NEVRA);
215 rpmlog(RPMLOG_ERR, _("Missing rpmlib features for %s:\n"), nvr);
217 rpmlog(RPMLOG_ERR, "\t%s\n", rpmdsDNEVR(req)+2);
227 rpmRC rpmInstallSourcePackage(rpmts ts, FD_t fd,
228 char ** specFilePtr, char ** cookie)
231 char * specFile = NULL;
232 const char *rootdir = rpmtsRootDir(ts);
238 struct rpmtd_s filenames;
240 rpmtdReset(&filenames);
241 rpmrc = rpmReadPackageFile(ts, fd, NULL, &h);
243 case RPMRC_NOTTRUSTED:
254 rpmrc = RPMRC_FAIL; /* assume failure */
256 if (!headerIsSource(h)) {
257 rpmlog(RPMLOG_ERR, _("source package expected, binary found\n"));
261 /* src.rpm install can require specific rpmlib features, check them */
265 if (headerGet(h, RPMTAG_BASENAMES, &filenames, HEADERGET_ALLOC)) {
268 const char *_cookie = headerGetString(h, RPMTAG_COOKIE);
269 if (cookie && _cookie) *cookie = xstrdup(_cookie);
271 /* Try to find spec by file flags */
272 if (_cookie && headerGet(h, RPMTAG_FILEFLAGS, &td, HEADERGET_MINMEM)) {
274 while (specix < 0 && (flags = rpmtdNextUint32(&td))) {
275 if (*flags & RPMFILE_SPECFILE)
276 specix = rpmtdGetIndex(&td);
279 /* Still no spec? Look by filename. */
280 while (specix < 0 && (str = rpmtdNextString(&filenames))) {
281 if (rpmFileHasSuffix(str, ".spec"))
282 specix = rpmtdGetIndex(&filenames);
286 if (rootdir && rstreq(rootdir, "/"))
289 /* Macros need to be added before trying to create directories */
290 rpmInstallLoadMacros(h);
295 headerDel(h, RPMTAG_BASENAMES);
296 headerDel(h, RPMTAG_DIRNAMES);
297 headerDel(h, RPMTAG_DIRINDEXES);
299 rpmtdInit(&filenames);
300 for (int i = 0; (bn = rpmtdNextString(&filenames)); i++) {
301 int spec = (i == specix);
302 char *fn = rpmGenPath(rpmtsRootDir(ts),
303 spec ? "%{_specdir}" : "%{_sourcedir}", bn);
304 headerPutString(h, RPMTAG_OLDFILENAMES, fn);
305 if (spec) specFile = xstrdup(fn);
308 headerConvert(h, HEADERCONV_COMPRESSFILELIST);
310 rpmlog(RPMLOG_ERR, _("source package contains no .spec file\n"));
314 if (rpmtsAddInstallElement(ts, h, NULL, 0, NULL)) {
318 te = rpmtsElement(ts, 0);
319 if (te == NULL) { /* XXX can't happen */
324 rpmteSetHeader(te, h);
325 fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, RPMFI_KEEPHEADER);
331 fi->apath = filenames.data; /* Ick */
335 if (rpmMkdirs(rpmtsRootDir(ts), "%{_topdir}:%{_sourcedir}:%{_specdir}")) {
340 /* set all files to be installed */
341 rpmfs fs = rpmteGetFileStates(te);
343 unsigned int fc = rpmfiFC(fi);
344 for (i=0; i<fc; i++) rpmfsSetAction(fs, i, FA_CREATE);
347 psm = rpmpsmNew(ts, te);
348 psm->goal = PKG_INSTALL;
350 /* FIX: psm->fi->dnl should be owned. */
351 if (rpmpsmStage(psm, PSM_PROCESS) == RPMRC_OK)
354 (void) rpmpsmStage(psm, PSM_FINI);
358 if (specFilePtr && specFile && rpmrc == RPMRC_OK)
359 *specFilePtr = specFile;
366 /* XXX nuke the added package(s). */
372 static rpmTagVal triggertag(rpmsenseFlags sense)
374 rpmTagVal tag = RPMTAG_NOT_FOUND;
376 case RPMSENSE_TRIGGERIN:
377 tag = RPMTAG_TRIGGERIN;
379 case RPMSENSE_TRIGGERUN:
380 tag = RPMTAG_TRIGGERUN;
382 case RPMSENSE_TRIGGERPOSTUN:
383 tag = RPMTAG_TRIGGERPOSTUN;
385 case RPMSENSE_TRIGGERPREIN:
386 tag = RPMTAG_TRIGGERPREIN;
395 * Run a scriptlet with args.
397 * Run a script with an interpreter. If the interpreter is not specified,
398 * /bin/sh will be used. If the interpreter is /bin/sh, then the args from
399 * the header will be ignored, passing instead arg1 and arg2.
401 * @param psm package state machine data
402 * @param prefixes install prefixes
403 * @param script scriptlet from header
404 * @param arg1 no. instances of package installed after scriptlet exec
406 * @param arg2 ditto, but for the target package
407 * @return 0 on success
409 static rpmRC runScript(rpmpsm psm, ARGV_const_t prefixes,
410 rpmScript script, int arg1, int arg2)
412 rpmRC stoprc, rc = RPMRC_OK;
413 rpmTagVal stag = rpmScriptTag(script);
415 int warn_only = (stag != RPMTAG_PREIN &&
416 stag != RPMTAG_PREUN &&
417 stag != RPMTAG_PRETRANS &&
418 stag != RPMTAG_VERIFYSCRIPT);
419 int selinux = !(rpmtsFlags(psm->ts) & RPMTRANS_FLAG_NOCONTEXTS);
421 sfd = rpmtsNotify(psm->ts, psm->te, RPMCALLBACK_SCRIPT_START, stag, 0);
423 sfd = rpmtsScriptFd(psm->ts);
425 rpmtsSuspendResumeDBLock(psm->ts, 0);
426 rpmswEnter(rpmtsOp(psm->ts, RPMTS_OP_SCRIPTLETS), 0);
427 rc = rpmScriptRun(script, arg1, arg2, sfd,
428 prefixes, warn_only, selinux, psm->ts->plugins);
429 rpmswExit(rpmtsOp(psm->ts, RPMTS_OP_SCRIPTLETS), 0);
430 rpmtsSuspendResumeDBLock(psm->ts, 1);
432 /* Map warn-only errors to "notfound" for script stop callback */
433 stoprc = (rc != RPMRC_OK && warn_only) ? RPMRC_NOTFOUND : rc;
434 rpmtsNotify(psm->ts, psm->te, RPMCALLBACK_SCRIPT_STOP, stag, stoprc);
437 * Notify callback for all errors. "total" abused for warning/error,
438 * rc only reflects whether the condition prevented install/erase
439 * (which is only happens with %prein and %preun scriptlets) or not.
441 if (rc != RPMRC_OK) {
445 rpmtsNotify(psm->ts, psm->te, RPMCALLBACK_SCRIPT_ERROR, stag, rc);
451 static rpmRC runInstScript(rpmpsm psm)
455 Header h = rpmteHeader(psm->te);
456 rpmScript script = rpmScriptFromTag(h, psm->scriptTag);
459 headerGet(h, RPMTAG_INSTPREFIXES, &pfx, HEADERGET_ALLOC|HEADERGET_ARGV);
460 rc = runScript(psm, pfx.data, script, psm->scriptArg, -1);
464 rpmScriptFree(script);
472 * @todo Trigger on any provides, not just package NVR.
473 * @param psm package state machine data
474 * @param sourceH header of trigger source
475 * @param trigH header of triggered package
477 * @param triggersAlreadyRun
480 static rpmRC handleOneTrigger(const rpmpsm psm,
481 Header sourceH, Header trigH,
482 int arg2, unsigned char * triggersAlreadyRun)
484 const rpmts ts = psm->ts;
485 rpmds trigger = rpmdsInit(rpmdsNew(trigH, RPMTAG_TRIGGERNAME, 0));
487 const char * sourceName = headerGetString(sourceH, RPMTAG_NAME);
488 const char * triggerName = headerGetString(trigH, RPMTAG_NAME);
495 headerGet(trigH, RPMTAG_INSTPREFIXES, &pfx, HEADERGET_ALLOC|HEADERGET_ARGV);
496 (void) rpmdsSetNoPromote(trigger, 1);
498 while ((i = rpmdsNext(trigger)) >= 0) {
499 struct rpmtd_s tindexes;
502 if (!(rpmdsFlags(trigger) & psm->sense))
505 if (!rstreq(rpmdsN(trigger), sourceName))
508 /* XXX Trigger on any provided dependency, not just the package NEVR */
509 if (!rpmdsAnyMatchesDep(sourceH, trigger, 1))
512 if (!headerGet(trigH, RPMTAG_TRIGGERINDEX, &tindexes, HEADERGET_MINMEM))
515 if (rpmtdSetIndex(&tindexes, i) < 0) {
516 rpmtdFreeData(&tindexes);
520 tix = rpmtdGetNumber(&tindexes);
521 if (triggersAlreadyRun == NULL || triggersAlreadyRun[tix] == 0) {
522 int arg1 = rpmdbCountPackages(rpmtsGetRdb(ts), triggerName);
525 /* XXX W2DO? fails as "execution of script failed" */
528 rpmScript script = rpmScriptFromTriggerTag(trigH,
529 triggertag(psm->sense), tix);
530 arg1 += psm->countCorrection;
531 rc = runScript(psm, pfx.data, script, arg1, arg2);
533 if (triggersAlreadyRun != NULL)
534 triggersAlreadyRun[tix] = 1;
536 rpmScriptFree(script);
540 rpmtdFreeData(&tindexes);
543 * Each target/source header pair can only result in a single
556 * Run trigger scripts in the database that are fired by this header.
557 * @param psm package state machine data
558 * @return 0 on success
560 static rpmRC runTriggers(rpmpsm psm)
562 const rpmts ts = psm->ts;
564 const char * N = NULL;
567 if (psm->te) /* XXX can't happen */
569 if (N) /* XXX can't happen */
570 numPackage = rpmdbCountPackages(rpmtsGetRdb(ts), N)
571 + psm->countCorrection;
573 return RPMRC_NOTFOUND;
576 Header h = rpmteHeader(psm->te);
577 rpmdbMatchIterator mi;
578 int countCorrection = psm->countCorrection;
580 psm->countCorrection = 0;
581 mi = rpmtsInitIterator(ts, RPMDBI_TRIGGERNAME, N, 0);
582 while((triggeredH = rpmdbNextIterator(mi)) != NULL)
583 nerrors += handleOneTrigger(psm, h, triggeredH, numPackage, NULL);
584 rpmdbFreeIterator(mi);
585 psm->countCorrection = countCorrection;
589 return (nerrors == 0) ? RPMRC_OK : RPMRC_FAIL;
593 * Run triggers from this header that are fired by headers in the database.
594 * @param psm package state machine data
595 * @return 0 on success
597 static rpmRC runImmedTriggers(rpmpsm psm)
599 const rpmts ts = psm->ts;
600 unsigned char * triggersRun;
601 struct rpmtd_s tnames, tindexes;
602 Header h = rpmteHeader(psm->te);
605 if (!(headerGet(h, RPMTAG_TRIGGERNAME, &tnames, HEADERGET_MINMEM) &&
606 headerGet(h, RPMTAG_TRIGGERINDEX, &tindexes, HEADERGET_MINMEM))) {
610 triggersRun = xcalloc(rpmtdCount(&tindexes), sizeof(*triggersRun));
611 { Header sourceH = NULL;
612 const char *trigName;
613 rpm_count_t *triggerIndices = tindexes.data;
615 while ((trigName = rpmtdNextString(&tnames))) {
616 rpmdbMatchIterator mi;
617 int i = rpmtdGetIndex(&tnames);
619 if (triggersRun[triggerIndices[i]] != 0) continue;
621 mi = rpmtsInitIterator(ts, RPMDBI_NAME, trigName, 0);
623 while((sourceH = rpmdbNextIterator(mi)) != NULL) {
624 nerrors += handleOneTrigger(psm, sourceH, h,
625 rpmdbGetIteratorCount(mi),
629 rpmdbFreeIterator(mi);
632 rpmtdFreeData(&tnames);
633 rpmtdFreeData(&tindexes);
638 return (nerrors == 0) ? RPMRC_OK : RPMRC_FAIL;
641 static rpmpsm rpmpsmFree(rpmpsm psm)
646 /* XXX rpmte not refcounted yet */
647 memset(psm, 0, sizeof(*psm)); /* XXX trash and burn */
653 static rpmpsm rpmpsmNew(rpmts ts, rpmte te)
655 rpmpsm psm = xcalloc(1, sizeof(*psm));
656 psm->ts = rpmtsLink(ts);
657 psm->fi = rpmfiLink(rpmteFI(te));
658 psm->te = te; /* XXX rpmte not refcounted yet */
662 void rpmpsmNotify(rpmpsm psm, int what, rpm_loff_t amount)
666 if (amount > psm->amount) {
667 psm->amount = amount;
670 if (what && what != psm->what) {
675 rpmtsNotify(psm->ts, psm->te, psm->what, psm->amount, psm->total);
681 * --replacepkgs hack: find the header instance we're replacing and
682 * mark it as the db instance of the install element. In PSM_POST,
683 * if an install element already has a db instance, it's removed
684 * before proceeding with the adding the new header to the db.
686 static void markReplacedInstance(rpmts ts, rpmte te)
688 /* this must match rpmNameVersionCompare in depends.c */
689 rpmdbMatchIterator mi = rpmtsInitIterator(ts, RPMDBI_NAME, rpmteN(te), 0);
690 rpmdbSetIteratorRE(mi, RPMTAG_EPOCH, RPMMIRE_STRCMP, rpmteE(te));
691 rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_STRCMP, rpmteV(te));
692 rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_STRCMP, rpmteR(te));
693 rpmdbSetIteratorRE(mi, RPMTAG_ARCH, RPMMIRE_STRCMP, rpmteA(te));
694 /* XXX shouldn't we also do this on colorless transactions? */
695 if (rpmtsColor(ts)) {
696 rpmdbSetIteratorRE(mi, RPMTAG_OS, RPMMIRE_STRCMP, rpmteO(te));
699 while (rpmdbNextIterator(mi) != NULL) {
700 rpmteSetDBInstance(te, rpmdbGetIteratorOffset(mi));
703 rpmdbFreeIterator(mi);
706 static rpmRC rpmpsmNext(rpmpsm psm, pkgStage nstage)
708 psm->nstage = nstage;
709 return rpmpsmStage(psm, psm->nstage);
712 static rpmRC rpmpsmStage(rpmpsm psm, pkgStage stage)
714 const rpmts ts = psm->ts;
722 rpmlog(RPMLOG_DEBUG, "%s: %s has %d files\n",
723 psm->goalName, rpmteNEVR(psm->te), rpmfiFC(fi));
726 * When we run scripts, we pass an argument which is the number of
727 * versions of this package that will be installed when we are
730 psm->npkgs_installed = rpmdbCountPackages(rpmtsGetRdb(ts), rpmteN(psm->te));
731 if (psm->npkgs_installed < 0) {
736 if (psm->goal == PKG_INSTALL) {
737 Header h = rpmteHeader(psm->te);
738 psm->scriptArg = psm->npkgs_installed + 1;
741 psm->total = headerGetNumber(h, RPMTAG_LONGARCHIVESIZE);
742 /* fake up something for packages with no files */
746 /* HACK: reinstall abuses te instance to remove old header */
747 if (rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEPKG)
748 markReplacedInstance(ts, psm->te);
750 if (rpmfiFC(fi) > 0) {
751 struct rpmtd_s filenames;
752 rpmTag ftag = RPMTAG_FILENAMES;
754 if (headerIsEntry(h, RPMTAG_ORIGBASENAMES)) {
755 ftag = RPMTAG_ORIGFILENAMES;
757 headerGet(h, ftag, &filenames, HEADERGET_EXT);
758 fi->apath = filenames.data; /* Ick.. */
762 if (psm->goal == PKG_ERASE) {
763 psm->scriptArg = psm->npkgs_installed - 1;
766 psm->total = rpmfiFC(fi) ? rpmfiFC(fi) : 100;
770 if (psm->goal == PKG_INSTALL) {
771 psm->scriptTag = RPMTAG_PREIN;
772 psm->sense = RPMSENSE_TRIGGERPREIN;
773 psm->countCorrection = 0; /* XXX is this correct?!? */
775 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERPREIN)) {
776 /* Run triggers in other package(s) this package sets off. */
777 rc = rpmpsmNext(psm, PSM_TRIGGERS);
780 /* Run triggers in this package other package(s) set off. */
781 rc = rpmpsmNext(psm, PSM_IMMED_TRIGGERS);
785 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPRE)) {
786 rc = rpmpsmNext(psm, PSM_SCRIPT);
791 if (psm->goal == PKG_ERASE) {
792 psm->scriptTag = RPMTAG_PREUN;
793 psm->sense = RPMSENSE_TRIGGERUN;
794 psm->countCorrection = -1;
796 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERUN)) {
797 /* Run triggers in this package other package(s) set off. */
798 rc = rpmpsmNext(psm, PSM_IMMED_TRIGGERS);
801 /* Run triggers in other package(s) this package sets off. */
802 rc = rpmpsmNext(psm, PSM_TRIGGERS);
806 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPREUN))
807 rc = rpmpsmNext(psm, PSM_SCRIPT);
811 if (psm->goal == PKG_INSTALL) {
814 rpmpsmNotify(psm, RPMCALLBACK_INST_START, 0);
815 /* make sure first progress call gets made */
816 rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, 0);
818 if (rpmfiFC(fi) > 0 && !(rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)) {
819 rpmtransFlags oldtsflags;
820 FD_t payload = rpmtePayload(psm->te);
821 if (payload == NULL) {
826 oldtsflags = rpmtsFlags(ts);
827 if (headerIsEntry(fi->h, RPMTAG_REMOVETID))
828 (void) rpmtsSetFlags(ts, oldtsflags | RPMTRANS_FLAG_NOMD5);
830 fsmrc = rpmPackageFilesInstall(psm->ts, psm->te, psm->fi,
831 payload, psm, &psm->failedFile);
833 rpmswAdd(rpmtsOp(psm->ts, RPMTS_OP_UNCOMPRESS),
834 fdOp(payload, FDSTAT_READ));
835 rpmswAdd(rpmtsOp(psm->ts, RPMTS_OP_DIGEST),
836 fdOp(payload, FDSTAT_DIGEST));
838 if (headerIsEntry(fi->h, RPMTAG_REMOVETID))
839 (void) rpmtsSetFlags(ts, oldtsflags);
844 /* XXX make sure progress reaches 100% */
845 rpmpsmNotify(psm, 0, psm->total);
846 rpmpsmNotify(psm, RPMCALLBACK_INST_STOP, psm->total);
850 _("unpacking of archive failed%s%s: %s\n"),
851 (psm->failedFile != NULL ? _(" on file ") : ""),
852 (psm->failedFile != NULL ? psm->failedFile : ""),
853 rpmcpioStrerror(fsmrc));
856 /* XXX notify callback on error. */
857 rpmtsNotify(ts, psm->te, RPMCALLBACK_UNPACK_ERROR, 0, 0);
861 if (psm->goal == PKG_ERASE) {
862 if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB) break;
864 rpmpsmNotify(psm, RPMCALLBACK_UNINST_START, 0);
865 /* make sure first progress call gets made */
866 rpmpsmNotify(psm, RPMCALLBACK_UNINST_PROGRESS, 0);
868 /* XXX should't we log errors from here? */
869 if (rpmfiFC(fi) > 0 && !(rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)) {
870 rc = rpmPackageFilesRemove(psm->ts, psm->te, psm->fi,
871 psm, &psm->failedFile);
874 /* XXX make sure progress reaches 100% */
875 rpmpsmNotify(psm, 0, psm->total);
876 rpmpsmNotify(psm, RPMCALLBACK_UNINST_STOP, psm->total);
880 if (psm->goal == PKG_INSTALL) {
881 rpm_time_t installTime = (rpm_time_t) time(NULL);
882 rpmfs fs = rpmteGetFileStates(psm->te);
883 rpm_count_t fc = rpmfsFC(fs);
884 rpm_fstate_t * fileStates = rpmfsGetStates(fs);
885 Header h = rpmteHeader(psm->te);
886 rpm_color_t tscolor = rpmtsColor(ts);
888 if (fileStates != NULL && fc > 0) {
889 headerPutChar(h, RPMTAG_FILESTATES, fileStates, fc);
892 headerPutUint32(h, RPMTAG_INSTALLTIME, &installTime, 1);
893 headerPutUint32(h, RPMTAG_INSTALLCOLOR, &tscolor, 1);
897 * If this package has already been installed, remove it from
898 * the database before adding the new one.
900 if (rpmteDBInstance(psm->te)) {
901 rc = rpmpsmNext(psm, PSM_RPMDB_REMOVE);
905 rc = rpmpsmNext(psm, PSM_RPMDB_ADD);
908 psm->scriptTag = RPMTAG_POSTIN;
909 psm->sense = RPMSENSE_TRIGGERIN;
910 psm->countCorrection = 0;
912 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPOST)) {
913 rc = rpmpsmNext(psm, PSM_SCRIPT);
916 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERIN)) {
917 /* Run triggers in other package(s) this package sets off. */
918 rc = rpmpsmNext(psm, PSM_TRIGGERS);
921 /* Run triggers in this package other package(s) set off. */
922 rc = rpmpsmNext(psm, PSM_IMMED_TRIGGERS);
926 rc = markReplacedFiles(psm);
929 if (psm->goal == PKG_ERASE) {
931 psm->scriptTag = RPMTAG_POSTUN;
932 psm->sense = RPMSENSE_TRIGGERPOSTUN;
933 psm->countCorrection = -1;
935 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPOSTUN)) {
936 rc = rpmpsmNext(psm, PSM_SCRIPT);
940 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERPOSTUN)) {
941 /* Run triggers in other package(s) this package sets off. */
942 rc = rpmpsmNext(psm, PSM_TRIGGERS);
946 rc = rpmpsmNext(psm, PSM_RPMDB_REMOVE);
955 _("%s failed on file %s: %s\n"),
956 psm->goalName, psm->failedFile, rpmcpioStrerror(rc));
958 rpmlog(RPMLOG_ERR, _("%s failed: %s\n"),
959 psm->goalName, rpmcpioStrerror(rc));
961 /* XXX notify callback on error. */
962 rpmtsNotify(ts, psm->te, RPMCALLBACK_CPIO_ERROR, 0, 0);
965 psm->failedFile = _free(psm->failedFile);
967 fi->apath = _free(fi->apath);
974 case PSM_SCRIPT: /* Run current package scriptlets. */
975 rc = runInstScript(psm);
978 /* Run triggers in other package(s) this package sets off. */
979 rc = runTriggers(psm);
981 case PSM_IMMED_TRIGGERS:
982 /* Run triggers in this package other package(s) set off. */
983 rc = runImmedTriggers(psm);
986 case PSM_RPMDB_ADD: {
987 Header h = rpmteHeader(psm->te);
989 if (!headerIsEntry(h, RPMTAG_INSTALLTID)) {
990 rpm_tid_t tid = rpmtsGetTid(ts);
991 if (tid != 0 && tid != (rpm_tid_t)-1)
992 headerPutUint32(h, RPMTAG_INSTALLTID, &tid, 1);
995 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DBADD), 0);
996 rc = (rpmdbAdd(rpmtsGetRdb(ts), h) == 0) ? RPMRC_OK : RPMRC_FAIL;
997 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DBADD), 0);
1000 rpmteSetDBInstance(psm->te, headerGetInstance(h));
1004 case PSM_RPMDB_REMOVE:
1005 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DBREMOVE), 0);
1006 rc = (rpmdbRemove(rpmtsGetRdb(ts), rpmteDBInstance(psm->te)) == 0) ?
1007 RPMRC_OK : RPMRC_FAIL;
1008 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DBREMOVE), 0);
1010 rpmteSetDBInstance(psm->te, 0);
1020 static const char * pkgGoalString(pkgGoal goal)
1023 case PKG_INSTALL: return " install";
1024 case PKG_ERASE: return " erase";
1025 case PKG_VERIFY: return " verify";
1026 case PKG_PRETRANS: return " pretrans";
1027 case PKG_POSTTRANS: return "posttrans";
1028 default: return "unknown";
1032 rpmRC rpmpsmRun(rpmts ts, rpmte te, pkgGoal goal)
1035 rpmRC rc = RPMRC_FAIL;
1037 /* Psm can't fail in test mode, just return early */
1038 if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)
1041 psm = rpmpsmNew(ts, te);
1042 if (rpmChrootIn() == 0) {
1045 psm->goalName = pkgGoalString(goal);
1050 /* Run pre transaction element hook for all plugins */
1051 if (rpmpluginsCallPsmPre(ts->plugins, te) != RPMRC_FAIL) {
1053 op = (goal == PKG_INSTALL) ? RPMTS_OP_INSTALL : RPMTS_OP_ERASE;
1054 rpmswEnter(rpmtsOp(psm->ts, op), 0);
1056 rc = rpmpsmNext(psm, PSM_INIT);
1057 if (!rc) rc = rpmpsmNext(psm, PSM_PRE);
1058 if (!rc) rc = rpmpsmNext(psm, PSM_PROCESS);
1059 if (!rc) rc = rpmpsmNext(psm, PSM_POST);
1060 (void) rpmpsmNext(psm, PSM_FINI);
1062 rpmswExit(rpmtsOp(psm->ts, op), 0);
1065 /* Run post transaction element hook for all plugins */
1066 rpmpluginsCallPsmPost(ts->plugins, te, rc);
1071 psm->scriptTag = goal;
1072 rc = rpmpsmStage(psm, PSM_SCRIPT);
1077 /* XXX an error here would require a full abort */
1078 (void) rpmChrootOut();