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/rpmscript.h"
30 typedef enum pkgStage_e {
44 PSM_IMMED_TRIGGERS = 55,
52 rpmts ts; /*!< transaction set */
53 rpmte te; /*!< current transaction element */
54 rpmfi fi; /*!< transaction element file info */
55 const char * goalName;
57 rpmTagVal scriptTag; /*!< Scriptlet data tag. */
58 int npkgs_installed; /*!< No. of installed instances. */
59 int scriptArg; /*!< Scriptlet package arg. */
60 rpmsenseFlags sense; /*!< One of RPMSENSE_TRIGGER{PREIN,IN,UN,POSTUN}. */
61 int countCorrection; /*!< 0 if installing, -1 if removing. */
62 rpmCallbackType what; /*!< Callback type. */
63 rpm_loff_t amount; /*!< Callback amount. */
64 rpm_loff_t total; /*!< Callback total. */
66 pkgStage stage; /*!< Current psm stage. */
67 pkgStage nstage; /*!< Next psm stage. */
69 int nrefs; /*!< Reference count. */
72 static rpmpsm rpmpsmNew(rpmts ts, rpmte te);
73 static rpmpsm rpmpsmFree(rpmpsm psm);
74 static rpmRC rpmpsmStage(rpmpsm psm, pkgStage stage);
77 * Macros to be defined from per-header tag values.
78 * @todo Should other macros be added from header when installing a package?
80 static struct tagMacro {
81 const char *macroname; /*!< Macro name to define. */
82 rpmTag tag; /*!< Header tag to use for value. */
83 } const tagMacros[] = {
84 { "name", RPMTAG_NAME },
85 { "version", RPMTAG_VERSION },
86 { "release", RPMTAG_RELEASE },
87 { "epoch", RPMTAG_EPOCH },
92 * Define per-header macros.
96 static void rpmInstallLoadMacros(Header h)
98 const struct tagMacro * tagm;
100 for (tagm = tagMacros; tagm->macroname != NULL; tagm++) {
103 if (!headerGet(h, tagm->tag, &td, HEADERGET_DEFAULT))
106 switch (rpmtdType(&td)) {
108 body = rpmtdFormat(&td, RPMTD_FORMAT_STRING, NULL);
109 addMacro(NULL, tagm->macroname, NULL, body, -1);
120 * Adjust file states in database for files shared with this package:
121 * currently either "replaced" or "wrong color".
122 * @param psm package state machine data
125 static rpmRC markReplacedFiles(const rpmpsm psm)
127 const rpmts ts = psm->ts;
128 rpmfs fs = rpmteGetFileStates(psm->te);
129 sharedFileInfo replaced = rpmfsGetReplaced(fs);
131 rpmdbMatchIterator mi;
141 for (sfi = replaced; sfi; sfi=rpmfsNextReplaced(fs, sfi)) {
142 if (prev && prev == sfi->otherPkg)
144 prev = sfi->otherPkg;
150 offsets = xmalloc(num * sizeof(*offsets));
153 for (sfi = replaced; sfi; sfi=rpmfsNextReplaced(fs, sfi)) {
154 if (prev && prev == sfi->otherPkg)
156 prev = sfi->otherPkg;
157 offsets[num++] = sfi->otherPkg;
160 mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, NULL, 0);
161 rpmdbAppendIterator(mi, offsets, num);
162 rpmdbSetIteratorRewrite(mi, 1);
165 while ((h = rpmdbNextIterator(mi)) != NULL) {
167 struct rpmtd_s secStates;
170 if (!headerGet(h, RPMTAG_FILESTATES, &secStates, HEADERGET_MINMEM))
173 prev = rpmdbGetIteratorOffset(mi);
175 while (sfi && sfi->otherPkg == prev) {
176 int ix = rpmtdSetIndex(&secStates, sfi->otherFileNum);
179 char *state = rpmtdGetChar(&secStates);
180 if (state && *state != sfi->rstate) {
181 *state = sfi->rstate;
183 /* Modified header will be rewritten. */
185 rpmdbSetIteratorModified(mi, modified);
189 sfi=rpmfsNextReplaced(fs, sfi);
191 rpmtdFreeData(&secStates);
193 rpmdbFreeIterator(mi);
199 static int rpmlibDeps(Header h)
201 rpmds req = rpmdsInit(rpmdsNew(h, RPMTAG_REQUIRENAME, 0));
203 rpmdsRpmlib(&rpmlib, NULL);
206 while (rpmdsNext(req) >= 0) {
207 if (!(rpmdsFlags(req) & RPMSENSE_RPMLIB))
209 if (rpmdsSearch(rpmlib, req) < 0) {
211 nvr = headerGetAsString(h, RPMTAG_NEVRA);
212 rpmlog(RPMLOG_ERR, _("Missing rpmlib features for %s:\n"), nvr);
214 rpmlog(RPMLOG_ERR, "\t%s\n", rpmdsDNEVR(req)+2);
224 rpmRC rpmInstallSourcePackage(rpmts ts, FD_t fd,
225 char ** specFilePtr, char ** cookie)
228 char * specFile = NULL;
229 const char *rootdir = rpmtsRootDir(ts);
235 struct rpmtd_s filenames;
237 rpmtdReset(&filenames);
238 rpmrc = rpmReadPackageFile(ts, fd, NULL, &h);
240 case RPMRC_NOTTRUSTED:
251 rpmrc = RPMRC_FAIL; /* assume failure */
253 if (!headerIsSource(h)) {
254 rpmlog(RPMLOG_ERR, _("source package expected, binary found\n"));
258 /* src.rpm install can require specific rpmlib features, check them */
262 if (headerGet(h, RPMTAG_BASENAMES, &filenames, HEADERGET_ALLOC)) {
265 const char *_cookie = headerGetString(h, RPMTAG_COOKIE);
266 if (cookie && _cookie) *cookie = xstrdup(_cookie);
268 /* Try to find spec by file flags */
269 if (_cookie && headerGet(h, RPMTAG_FILEFLAGS, &td, HEADERGET_MINMEM)) {
271 while (specix < 0 && (flags = rpmtdNextUint32(&td))) {
272 if (*flags & RPMFILE_SPECFILE)
273 specix = rpmtdGetIndex(&td);
276 /* Still no spec? Look by filename. */
277 while (specix < 0 && (str = rpmtdNextString(&filenames))) {
278 if (rpmFileHasSuffix(str, ".spec"))
279 specix = rpmtdGetIndex(&filenames);
283 if (rootdir && rstreq(rootdir, "/"))
286 /* Macros need to be added before trying to create directories */
287 rpmInstallLoadMacros(h);
292 headerDel(h, RPMTAG_BASENAMES);
293 headerDel(h, RPMTAG_DIRNAMES);
294 headerDel(h, RPMTAG_DIRINDEXES);
296 rpmtdInit(&filenames);
297 for (int i = 0; (bn = rpmtdNextString(&filenames)); i++) {
298 int spec = (i == specix);
299 char *fn = rpmGenPath(rpmtsRootDir(ts),
300 spec ? "%{_specdir}" : "%{_sourcedir}", bn);
301 headerPutString(h, RPMTAG_OLDFILENAMES, fn);
302 if (spec) specFile = xstrdup(fn);
305 headerConvert(h, HEADERCONV_COMPRESSFILELIST);
307 rpmlog(RPMLOG_ERR, _("source package contains no .spec file\n"));
311 if (rpmtsAddInstallElement(ts, h, NULL, 0, NULL)) {
315 te = rpmtsElement(ts, 0);
316 if (te == NULL) { /* XXX can't happen */
321 rpmteSetHeader(te, h);
322 fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, RPMFI_KEEPHEADER);
328 fi->apath = filenames.data; /* Ick */
332 if (rpmMkdirs(rpmtsRootDir(ts), "%{_topdir}:%{_sourcedir}:%{_specdir}")) {
337 /* set all files to be installed */
338 rpmfs fs = rpmteGetFileStates(te);
340 unsigned int fc = rpmfiFC(fi);
341 for (i=0; i<fc; i++) rpmfsSetAction(fs, i, FA_CREATE);
344 psm = rpmpsmNew(ts, te);
345 psm->goal = PKG_INSTALL;
347 /* FIX: psm->fi->dnl should be owned. */
348 if (rpmpsmStage(psm, PSM_PROCESS) == RPMRC_OK)
351 (void) rpmpsmStage(psm, PSM_FINI);
355 if (specFilePtr && specFile && rpmrc == RPMRC_OK)
356 *specFilePtr = specFile;
363 /* XXX nuke the added package(s). */
369 static rpmTagVal triggertag(rpmsenseFlags sense)
371 rpmTagVal tag = RPMTAG_NOT_FOUND;
373 case RPMSENSE_TRIGGERIN:
374 tag = RPMTAG_TRIGGERIN;
376 case RPMSENSE_TRIGGERUN:
377 tag = RPMTAG_TRIGGERUN;
379 case RPMSENSE_TRIGGERPOSTUN:
380 tag = RPMTAG_TRIGGERPOSTUN;
382 case RPMSENSE_TRIGGERPREIN:
383 tag = RPMTAG_TRIGGERPREIN;
392 * Run a scriptlet with args.
394 * Run a script with an interpreter. If the interpreter is not specified,
395 * /bin/sh will be used. If the interpreter is /bin/sh, then the args from
396 * the header will be ignored, passing instead arg1 and arg2.
398 * @param psm package state machine data
399 * @param prefixes install prefixes
400 * @param script scriptlet from header
401 * @param arg1 no. instances of package installed after scriptlet exec
403 * @param arg2 ditto, but for the target package
404 * @return 0 on success
406 static rpmRC runScript(rpmpsm psm, ARGV_const_t prefixes,
407 rpmScript script, int arg1, int arg2)
409 rpmRC stoprc, rc = RPMRC_OK;
410 rpmTagVal stag = rpmScriptTag(script);
412 int warn_only = (stag != RPMTAG_PREIN &&
413 stag != RPMTAG_PREUN &&
414 stag != RPMTAG_PRETRANS &&
415 stag != RPMTAG_VERIFYSCRIPT);
416 int selinux = !(rpmtsFlags(psm->ts) & RPMTRANS_FLAG_NOCONTEXTS);
418 sfd = rpmtsNotify(psm->ts, psm->te, RPMCALLBACK_SCRIPT_START, stag, 0);
420 sfd = rpmtsScriptFd(psm->ts);
422 rpmswEnter(rpmtsOp(psm->ts, RPMTS_OP_SCRIPTLETS), 0);
423 rc = rpmScriptRun(script, arg1, arg2, sfd,
424 prefixes, warn_only, selinux);
425 rpmswExit(rpmtsOp(psm->ts, RPMTS_OP_SCRIPTLETS), 0);
427 /* Map warn-only errors to "notfound" for script stop callback */
428 stoprc = (rc != RPMRC_OK && warn_only) ? RPMRC_NOTFOUND : rc;
429 rpmtsNotify(psm->ts, psm->te, RPMCALLBACK_SCRIPT_STOP, stag, stoprc);
432 * Notify callback for all errors. "total" abused for warning/error,
433 * rc only reflects whether the condition prevented install/erase
434 * (which is only happens with %prein and %preun scriptlets) or not.
436 if (rc != RPMRC_OK) {
440 rpmtsNotify(psm->ts, psm->te, RPMCALLBACK_SCRIPT_ERROR, stag, rc);
446 static rpmRC runInstScript(rpmpsm psm)
450 Header h = rpmteHeader(psm->te);
451 rpmScript script = rpmScriptFromTag(h, psm->scriptTag);
454 headerGet(h, RPMTAG_INSTPREFIXES, &pfx, HEADERGET_ALLOC|HEADERGET_ARGV);
455 rc = runScript(psm, pfx.data, script, psm->scriptArg, -1);
459 rpmScriptFree(script);
467 * @todo Trigger on any provides, not just package NVR.
468 * @param psm package state machine data
469 * @param sourceH header of trigger source
470 * @param trigH header of triggered package
472 * @param triggersAlreadyRun
475 static rpmRC handleOneTrigger(const rpmpsm psm,
476 Header sourceH, Header trigH,
477 int arg2, unsigned char * triggersAlreadyRun)
479 const rpmts ts = psm->ts;
480 rpmds trigger = rpmdsInit(rpmdsNew(trigH, RPMTAG_TRIGGERNAME, 0));
482 const char * sourceName = headerGetString(sourceH, RPMTAG_NAME);
483 const char * triggerName = headerGetString(trigH, RPMTAG_NAME);
490 headerGet(trigH, RPMTAG_INSTPREFIXES, &pfx, HEADERGET_ALLOC|HEADERGET_ARGV);
491 (void) rpmdsSetNoPromote(trigger, 1);
493 while ((i = rpmdsNext(trigger)) >= 0) {
494 struct rpmtd_s tindexes;
497 if (!(rpmdsFlags(trigger) & psm->sense))
500 if (!rstreq(rpmdsN(trigger), sourceName))
503 /* XXX Trigger on any provided dependency, not just the package NEVR */
504 if (!rpmdsAnyMatchesDep(sourceH, trigger, 1))
507 if (!headerGet(trigH, RPMTAG_TRIGGERINDEX, &tindexes, HEADERGET_MINMEM))
510 if (rpmtdSetIndex(&tindexes, i) < 0) {
511 rpmtdFreeData(&tindexes);
515 tix = rpmtdGetNumber(&tindexes);
516 if (triggersAlreadyRun == NULL || triggersAlreadyRun[tix] == 0) {
517 int arg1 = rpmdbCountPackages(rpmtsGetRdb(ts), triggerName);
520 /* XXX W2DO? fails as "execution of script failed" */
523 rpmScript script = rpmScriptFromTriggerTag(trigH,
524 triggertag(psm->sense), tix);
525 arg1 += psm->countCorrection;
526 rc = runScript(psm, pfx.data, script, arg1, arg2);
528 if (triggersAlreadyRun != NULL)
529 triggersAlreadyRun[tix] = 1;
531 rpmScriptFree(script);
535 rpmtdFreeData(&tindexes);
538 * Each target/source header pair can only result in a single
551 * Run trigger scripts in the database that are fired by this header.
552 * @param psm package state machine data
553 * @return 0 on success
555 static rpmRC runTriggers(rpmpsm psm)
557 const rpmts ts = psm->ts;
559 const char * N = NULL;
562 if (psm->te) /* XXX can't happen */
564 if (N) /* XXX can't happen */
565 numPackage = rpmdbCountPackages(rpmtsGetRdb(ts), N)
566 + psm->countCorrection;
568 return RPMRC_NOTFOUND;
571 Header h = rpmteHeader(psm->te);
572 rpmdbMatchIterator mi;
573 int countCorrection = psm->countCorrection;
575 psm->countCorrection = 0;
576 mi = rpmtsInitIterator(ts, RPMDBI_TRIGGERNAME, N, 0);
577 while((triggeredH = rpmdbNextIterator(mi)) != NULL)
578 nerrors += handleOneTrigger(psm, h, triggeredH, numPackage, NULL);
579 rpmdbFreeIterator(mi);
580 psm->countCorrection = countCorrection;
584 return (nerrors == 0) ? RPMRC_OK : RPMRC_FAIL;
588 * Run triggers from this header that are fired by headers in the database.
589 * @param psm package state machine data
590 * @return 0 on success
592 static rpmRC runImmedTriggers(rpmpsm psm)
594 const rpmts ts = psm->ts;
595 unsigned char * triggersRun;
596 struct rpmtd_s tnames, tindexes;
597 Header h = rpmteHeader(psm->te);
600 if (!(headerGet(h, RPMTAG_TRIGGERNAME, &tnames, HEADERGET_MINMEM) &&
601 headerGet(h, RPMTAG_TRIGGERINDEX, &tindexes, HEADERGET_MINMEM))) {
605 triggersRun = xcalloc(rpmtdCount(&tindexes), sizeof(*triggersRun));
606 { Header sourceH = NULL;
607 const char *trigName;
608 rpm_count_t *triggerIndices = tindexes.data;
610 while ((trigName = rpmtdNextString(&tnames))) {
611 rpmdbMatchIterator mi;
612 int i = rpmtdGetIndex(&tnames);
614 if (triggersRun[triggerIndices[i]] != 0) continue;
616 mi = rpmtsInitIterator(ts, RPMDBI_NAME, trigName, 0);
618 while((sourceH = rpmdbNextIterator(mi)) != NULL) {
619 nerrors += handleOneTrigger(psm, sourceH, h,
620 rpmdbGetIteratorCount(mi),
624 rpmdbFreeIterator(mi);
627 rpmtdFreeData(&tnames);
628 rpmtdFreeData(&tindexes);
633 return (nerrors == 0) ? RPMRC_OK : RPMRC_FAIL;
636 static rpmpsm rpmpsmFree(rpmpsm psm)
641 /* XXX rpmte not refcounted yet */
642 memset(psm, 0, sizeof(*psm)); /* XXX trash and burn */
648 static rpmpsm rpmpsmNew(rpmts ts, rpmte te)
650 rpmpsm psm = xcalloc(1, sizeof(*psm));
651 psm->ts = rpmtsLink(ts);
652 psm->fi = rpmfiLink(rpmteFI(te));
653 psm->te = te; /* XXX rpmte not refcounted yet */
657 void rpmpsmNotify(rpmpsm psm, int what, rpm_loff_t amount)
661 if (amount > psm->amount) {
662 psm->amount = amount;
665 if (what && what != psm->what) {
670 rpmtsNotify(psm->ts, psm->te, psm->what, psm->amount, psm->total);
676 * --replacepkgs hack: find the header instance we're replacing and
677 * mark it as the db instance of the install element. In PSM_POST,
678 * if an install element already has a db instance, it's removed
679 * before proceeding with the adding the new header to the db.
681 static void markReplacedInstance(rpmts ts, rpmte te)
683 rpmdbMatchIterator mi = rpmtsInitIterator(ts, RPMDBI_NAME, rpmteN(te), 0);
684 rpmdbSetIteratorRE(mi, RPMTAG_EPOCH, RPMMIRE_STRCMP, rpmteE(te));
685 rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_STRCMP, rpmteV(te));
686 rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_STRCMP, rpmteR(te));
687 /* XXX shouldn't we also do this on colorless transactions? */
688 if (rpmtsColor(ts)) {
689 rpmdbSetIteratorRE(mi, RPMTAG_ARCH, RPMMIRE_STRCMP, rpmteA(te));
690 rpmdbSetIteratorRE(mi, RPMTAG_OS, RPMMIRE_STRCMP, rpmteO(te));
693 while (rpmdbNextIterator(mi) != NULL) {
694 rpmteSetDBInstance(te, rpmdbGetIteratorOffset(mi));
697 rpmdbFreeIterator(mi);
700 static rpmRC rpmpsmNext(rpmpsm psm, pkgStage nstage)
702 psm->nstage = nstage;
703 return rpmpsmStage(psm, psm->nstage);
706 static rpmRC rpmpsmStage(rpmpsm psm, pkgStage stage)
708 const rpmts ts = psm->ts;
716 rpmlog(RPMLOG_DEBUG, "%s: %s has %d files\n",
717 psm->goalName, rpmteNEVR(psm->te), rpmfiFC(fi));
720 * When we run scripts, we pass an argument which is the number of
721 * versions of this package that will be installed when we are
724 psm->npkgs_installed = rpmdbCountPackages(rpmtsGetRdb(ts), rpmteN(psm->te));
725 if (psm->npkgs_installed < 0) {
730 if (psm->goal == PKG_INSTALL) {
731 Header h = rpmteHeader(psm->te);
732 psm->scriptArg = psm->npkgs_installed + 1;
735 psm->total = headerGetNumber(h, RPMTAG_LONGARCHIVESIZE);
736 /* fake up something for packages with no files */
740 /* HACK: reinstall abuses te instance to remove old header */
741 if (rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEPKG)
742 markReplacedInstance(ts, psm->te);
744 if (rpmfiFC(fi) > 0) {
745 struct rpmtd_s filenames;
746 rpmTag ftag = RPMTAG_FILENAMES;
748 if (headerIsEntry(h, RPMTAG_ORIGBASENAMES)) {
749 ftag = RPMTAG_ORIGFILENAMES;
751 headerGet(h, ftag, &filenames, HEADERGET_EXT);
752 fi->apath = filenames.data; /* Ick.. */
756 if (psm->goal == PKG_ERASE) {
757 psm->scriptArg = psm->npkgs_installed - 1;
760 psm->total = rpmfiFC(fi) ? rpmfiFC(fi) : 100;
764 if (psm->goal == PKG_INSTALL) {
765 psm->scriptTag = RPMTAG_PREIN;
766 psm->sense = RPMSENSE_TRIGGERPREIN;
767 psm->countCorrection = 0; /* XXX is this correct?!? */
769 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERPREIN)) {
770 /* Run triggers in other package(s) this package sets off. */
771 rc = rpmpsmNext(psm, PSM_TRIGGERS);
774 /* Run triggers in this package other package(s) set off. */
775 rc = rpmpsmNext(psm, PSM_IMMED_TRIGGERS);
779 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPRE)) {
780 rc = rpmpsmNext(psm, PSM_SCRIPT);
785 if (psm->goal == PKG_ERASE) {
786 psm->scriptTag = RPMTAG_PREUN;
787 psm->sense = RPMSENSE_TRIGGERUN;
788 psm->countCorrection = -1;
790 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERUN)) {
791 /* Run triggers in this package other package(s) set off. */
792 rc = rpmpsmNext(psm, PSM_IMMED_TRIGGERS);
795 /* Run triggers in other package(s) this package sets off. */
796 rc = rpmpsmNext(psm, PSM_TRIGGERS);
800 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPREUN))
801 rc = rpmpsmNext(psm, PSM_SCRIPT);
805 if (psm->goal == PKG_INSTALL) {
808 rpmpsmNotify(psm, RPMCALLBACK_INST_START, 0);
809 /* make sure first progress call gets made */
810 rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, 0);
812 if (rpmfiFC(fi) > 0 && !(rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)) {
813 FD_t payload = rpmtePayload(psm->te);
814 if (payload == NULL) {
819 fsmrc = rpmfsmRun(FSM_PKGINSTALL, psm->ts, psm->te, psm->fi,
820 payload, psm, NULL, &psm->failedFile);
822 rpmswAdd(rpmtsOp(psm->ts, RPMTS_OP_UNCOMPRESS),
823 fdOp(payload, FDSTAT_READ));
824 rpmswAdd(rpmtsOp(psm->ts, RPMTS_OP_DIGEST),
825 fdOp(payload, FDSTAT_DIGEST));
830 /* XXX make sure progress reaches 100% */
831 rpmpsmNotify(psm, 0, psm->total);
832 rpmpsmNotify(psm, RPMCALLBACK_INST_STOP, psm->total);
836 _("unpacking of archive failed%s%s: %s\n"),
837 (psm->failedFile != NULL ? _(" on file ") : ""),
838 (psm->failedFile != NULL ? psm->failedFile : ""),
839 rpmcpioStrerror(fsmrc));
842 /* XXX notify callback on error. */
843 rpmtsNotify(ts, psm->te, RPMCALLBACK_UNPACK_ERROR, 0, 0);
847 if (psm->goal == PKG_ERASE) {
848 if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB) break;
850 rpmpsmNotify(psm, RPMCALLBACK_UNINST_START, 0);
851 /* make sure first progress call gets made */
852 rpmpsmNotify(psm, RPMCALLBACK_UNINST_PROGRESS, 0);
854 /* XXX should't we log errors from here? */
855 if (rpmfiFC(fi) > 0 && !(rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)) {
856 rc = rpmfsmRun(FSM_PKGERASE, psm->ts, psm->te, psm->fi,
857 NULL, psm, NULL, &psm->failedFile);
860 /* XXX make sure progress reaches 100% */
861 rpmpsmNotify(psm, 0, psm->total);
862 rpmpsmNotify(psm, RPMCALLBACK_UNINST_STOP, psm->total);
866 if (psm->goal == PKG_INSTALL) {
867 rpm_time_t installTime = (rpm_time_t) time(NULL);
868 rpmfs fs = rpmteGetFileStates(psm->te);
869 rpm_count_t fc = rpmfsFC(fs);
870 rpm_fstate_t * fileStates = rpmfsGetStates(fs);
871 Header h = rpmteHeader(psm->te);
872 rpm_color_t tscolor = rpmtsColor(ts);
874 if (fileStates != NULL && fc > 0) {
875 headerPutChar(h, RPMTAG_FILESTATES, fileStates, fc);
878 headerPutUint32(h, RPMTAG_INSTALLTIME, &installTime, 1);
879 headerPutUint32(h, RPMTAG_INSTALLCOLOR, &tscolor, 1);
883 * If this package has already been installed, remove it from
884 * the database before adding the new one.
886 if (rpmteDBInstance(psm->te)) {
887 rc = rpmpsmNext(psm, PSM_RPMDB_REMOVE);
891 rc = rpmpsmNext(psm, PSM_RPMDB_ADD);
894 psm->scriptTag = RPMTAG_POSTIN;
895 psm->sense = RPMSENSE_TRIGGERIN;
896 psm->countCorrection = 0;
898 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPOST)) {
899 rc = rpmpsmNext(psm, PSM_SCRIPT);
902 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERIN)) {
903 /* Run triggers in other package(s) this package sets off. */
904 rc = rpmpsmNext(psm, PSM_TRIGGERS);
907 /* Run triggers in this package other package(s) set off. */
908 rc = rpmpsmNext(psm, PSM_IMMED_TRIGGERS);
912 rc = markReplacedFiles(psm);
915 if (psm->goal == PKG_ERASE) {
917 psm->scriptTag = RPMTAG_POSTUN;
918 psm->sense = RPMSENSE_TRIGGERPOSTUN;
919 psm->countCorrection = -1;
921 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPOSTUN)) {
922 rc = rpmpsmNext(psm, PSM_SCRIPT);
926 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERPOSTUN)) {
927 /* Run triggers in other package(s) this package sets off. */
928 rc = rpmpsmNext(psm, PSM_TRIGGERS);
932 rc = rpmpsmNext(psm, PSM_RPMDB_REMOVE);
941 _("%s failed on file %s: %s\n"),
942 psm->goalName, psm->failedFile, rpmcpioStrerror(rc));
944 rpmlog(RPMLOG_ERR, _("%s failed: %s\n"),
945 psm->goalName, rpmcpioStrerror(rc));
947 /* XXX notify callback on error. */
948 rpmtsNotify(ts, psm->te, RPMCALLBACK_CPIO_ERROR, 0, 0);
951 psm->failedFile = _free(psm->failedFile);
953 fi->apath = _free(fi->apath);
960 case PSM_SCRIPT: /* Run current package scriptlets. */
961 rc = runInstScript(psm);
964 /* Run triggers in other package(s) this package sets off. */
965 rc = runTriggers(psm);
967 case PSM_IMMED_TRIGGERS:
968 /* Run triggers in this package other package(s) set off. */
969 rc = runImmedTriggers(psm);
972 case PSM_RPMDB_ADD: {
973 Header h = rpmteHeader(psm->te);
975 if (!headerIsEntry(h, RPMTAG_INSTALLTID)) {
976 rpm_tid_t tid = rpmtsGetTid(ts);
977 if (tid != 0 && tid != (rpm_tid_t)-1)
978 headerPutUint32(h, RPMTAG_INSTALLTID, &tid, 1);
981 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DBADD), 0);
982 rc = (rpmdbAdd(rpmtsGetRdb(ts), h) == 0) ? RPMRC_OK : RPMRC_FAIL;
983 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DBADD), 0);
986 rpmteSetDBInstance(psm->te, headerGetInstance(h));
990 case PSM_RPMDB_REMOVE:
991 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DBREMOVE), 0);
992 rc = (rpmdbRemove(rpmtsGetRdb(ts), rpmteDBInstance(psm->te)) == 0) ?
993 RPMRC_OK : RPMRC_FAIL;
994 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DBREMOVE), 0);
996 rpmteSetDBInstance(psm->te, 0);
1006 static const char * pkgGoalString(pkgGoal goal)
1009 case PKG_INSTALL: return " install";
1010 case PKG_ERASE: return " erase";
1011 case PKG_VERIFY: return " verify";
1012 case PKG_PRETRANS: return " pretrans";
1013 case PKG_POSTTRANS: return "posttrans";
1014 default: return "unknown";
1018 rpmRC rpmpsmRun(rpmts ts, rpmte te, pkgGoal goal)
1021 rpmRC rc = RPMRC_FAIL;
1023 /* Psm can't fail in test mode, just return early */
1024 if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)
1027 psm = rpmpsmNew(ts, te);
1028 if (rpmChrootIn() == 0) {
1031 psm->goalName = pkgGoalString(goal);
1036 op = (goal == PKG_INSTALL) ? RPMTS_OP_INSTALL : RPMTS_OP_ERASE;
1037 rpmswEnter(rpmtsOp(psm->ts, op), 0);
1039 rc = rpmpsmNext(psm, PSM_INIT);
1040 if (!rc) rc = rpmpsmNext(psm, PSM_PRE);
1041 if (!rc) rc = rpmpsmNext(psm, PSM_PROCESS);
1042 if (!rc) rc = rpmpsmNext(psm, PSM_POST);
1043 (void) rpmpsmNext(psm, PSM_FINI);
1045 rpmswExit(rpmtsOp(psm->ts, op), 0);
1050 psm->scriptTag = goal;
1051 rc = rpmpsmStage(psm, PSM_SCRIPT);
1056 /* XXX an error here would require a full abort */
1057 (void) rpmChrootOut();