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 {
48 PSM_IMMED_TRIGGERS = 55,
55 typedef struct rpmpsm_s {
56 rpmts ts; /*!< transaction set */
57 rpmte te; /*!< current transaction element */
58 rpmfi fi; /*!< transaction element file info */
59 const char * goalName;
61 rpmTagVal scriptTag; /*!< Scriptlet data tag. */
62 int npkgs_installed; /*!< No. of installed instances. */
63 int scriptArg; /*!< Scriptlet package arg. */
64 rpmsenseFlags sense; /*!< One of RPMSENSE_TRIGGER{PREIN,IN,UN,POSTUN}. */
65 int countCorrection; /*!< 0 if installing, -1 if removing. */
66 rpmCallbackType what; /*!< Callback type. */
67 rpm_loff_t amount; /*!< Callback amount. */
68 rpm_loff_t total; /*!< Callback total. */
70 pkgStage stage; /*!< Current psm stage. */
71 pkgStage nstage; /*!< Next psm stage. */
73 int nrefs; /*!< Reference count. */
76 static rpmpsm rpmpsmNew(rpmts ts, rpmte te);
77 static rpmpsm rpmpsmFree(rpmpsm psm);
78 static rpmRC rpmpsmStage(rpmpsm psm, pkgStage stage);
81 * Macros to be defined from per-header tag values.
82 * @todo Should other macros be added from header when installing a package?
84 static struct tagMacro {
85 const char *macroname; /*!< Macro name to define. */
86 rpmTag tag; /*!< Header tag to use for value. */
87 } const tagMacros[] = {
88 { "name", RPMTAG_NAME },
89 { "version", RPMTAG_VERSION },
90 { "release", RPMTAG_RELEASE },
91 { "epoch", RPMTAG_EPOCH },
96 * Define per-header macros.
100 static void rpmInstallLoadMacros(Header h)
102 const struct tagMacro * tagm;
104 for (tagm = tagMacros; tagm->macroname != NULL; tagm++) {
107 if (!headerGet(h, tagm->tag, &td, HEADERGET_DEFAULT))
110 switch (rpmtdType(&td)) {
112 body = rpmtdFormat(&td, RPMTD_FORMAT_STRING, NULL);
113 addMacro(NULL, tagm->macroname, NULL, body, -1);
124 * Mark files in database shared with this package as "replaced".
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 xx = rpmdbAppendIterator(mi, offsets, num);
165 xx = 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 != RPMFILE_STATE_REPLACED) {
184 *state = RPMFILE_STATE_REPLACED;
186 /* Modified header will be rewritten. */
188 xx = rpmdbSetIteratorModified(mi, modified);
192 sfi=rpmfsNextReplaced(fs, sfi);
194 rpmtdFreeData(&secStates);
196 mi = 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, RPMDBG_M("InstallSourcePackage"), &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);
328 if (fi == NULL) { /* XXX can't happen */
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);
355 psm = rpmpsmFree(psm);
358 if (specFilePtr && specFile && rpmrc == RPMRC_OK)
359 *specFilePtr = specFile;
361 specFile = _free(specFile);
363 if (h != NULL) h = headerFree(h);
364 if (fi != NULL) fi = rpmfiFree(fi);
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)
413 int warn_only = (script->tag != RPMTAG_PREIN &&
414 script->tag != RPMTAG_PREUN &&
415 script->tag != RPMTAG_VERIFYSCRIPT);
416 int selinux = !(rpmtsFlags(psm->ts) & RPMTRANS_FLAG_NOCONTEXTS);
418 rpmswEnter(rpmtsOp(psm->ts, RPMTS_OP_SCRIPTLETS), 0);
419 rc = rpmScriptRun(script, arg1, arg2, rpmtsScriptFd(psm->ts),
420 prefixes, warn_only, selinux);
421 rpmswExit(rpmtsOp(psm->ts, RPMTS_OP_SCRIPTLETS), 0);
424 * Notify callback for all errors. "total" abused for warning/error,
425 * rc only reflects whether the condition prevented install/erase
426 * (which is only happens with %prein and %preun scriptlets) or not.
428 if (rc != RPMRC_OK) {
432 rpmtsNotify(psm->ts, psm->te, RPMCALLBACK_SCRIPT_ERROR, script->tag, rc);
438 static rpmRC runInstScript(rpmpsm psm)
442 Header h = rpmteHeader(psm->te);
443 rpmScript script = rpmScriptFromTag(h, psm->scriptTag);
446 headerGet(h, RPMTAG_INSTPREFIXES, &pfx, HEADERGET_ALLOC|HEADERGET_ARGV);
447 rc = runScript(psm, pfx.data, script, psm->scriptArg, -1);
451 rpmScriptFree(script);
459 * @todo Trigger on any provides, not just package NVR.
460 * @param psm package state machine data
461 * @param sourceH header of trigger source
462 * @param trigH header of triggered package
464 * @param triggersAlreadyRun
467 static rpmRC handleOneTrigger(const rpmpsm psm,
468 Header sourceH, Header trigH,
469 int arg2, unsigned char * triggersAlreadyRun)
471 const rpmts ts = psm->ts;
472 rpmds trigger = rpmdsInit(rpmdsNew(trigH, RPMTAG_TRIGGERNAME, 0));
474 const char * sourceName = headerGetString(sourceH, RPMTAG_NAME);
475 const char * triggerName = headerGetString(trigH, RPMTAG_NAME);
482 headerGet(trigH, RPMTAG_INSTPREFIXES, &pfx, HEADERGET_ALLOC|HEADERGET_ARGV);
483 (void) rpmdsSetNoPromote(trigger, 1);
485 while ((i = rpmdsNext(trigger)) >= 0) {
486 struct rpmtd_s tscripts, tprogs, tindexes, tflags;
487 headerGetFlags hgflags = HEADERGET_MINMEM;
489 if (!(rpmdsFlags(trigger) & psm->sense))
492 if (!rstreq(rpmdsN(trigger), sourceName))
495 /* XXX Trigger on any provided dependency, not just the package NEVR */
496 if (!rpmdsAnyMatchesDep(sourceH, trigger, 1))
499 /* XXX FIXME: this leaks memory if scripts or progs retrieve fails */
500 if (!(headerGet(trigH, RPMTAG_TRIGGERINDEX, &tindexes, hgflags) &&
501 headerGet(trigH, RPMTAG_TRIGGERSCRIPTS, &tscripts, hgflags) &&
502 headerGet(trigH, RPMTAG_TRIGGERSCRIPTPROG, &tprogs, hgflags))) {
505 int arg1 = rpmdbCountPackages(rpmtsGetRdb(ts), triggerName);
506 char ** triggerScripts = tscripts.data;
507 char ** triggerProgs = tprogs.data;
508 uint32_t * triggerIndices = tindexes.data;
509 uint32_t * triggerFlags = NULL;
510 uint32_t ix = triggerIndices[i];
512 headerGet(trigH, RPMTAG_TRIGGERSCRIPTFLAGS, &tflags, hgflags);
513 triggerFlags = tflags.data;
516 /* XXX W2DO? fails as "execution of script failed" */
519 arg1 += psm->countCorrection;
521 if (triggersAlreadyRun == NULL || triggersAlreadyRun[ix] == 0) {
522 /* XXX TODO add rpmScript API to handle this, ugh */
524 char *qformat = NULL;
525 char *args[2] = { triggerProgs[ix], NULL };
526 struct rpmScript_s script = {
527 .tag = triggertag(psm->sense),
528 .body = triggerScripts[ix],
529 .flags = triggerFlags ? triggerFlags[ix] : 0,
533 if (script.body && (script.flags & RPMSCRIPT_EXPAND)) {
534 macro = rpmExpand(script.body, NULL);
537 if (script.body && (script.flags & RPMSCRIPT_QFORMAT)) {
538 qformat = headerFormat(trigH, script.body, NULL);
539 script.body = qformat;
542 rc = runScript(psm, pfx.data, &script, arg1, arg2);
543 if (triggersAlreadyRun != NULL)
544 triggersAlreadyRun[ix] = 1;
551 rpmtdFreeData(&tindexes);
552 rpmtdFreeData(&tscripts);
553 rpmtdFreeData(&tprogs);
556 * Each target/source header pair can only result in a single
563 trigger = rpmdsFree(trigger);
569 * Run trigger scripts in the database that are fired by this header.
570 * @param psm package state machine data
571 * @return 0 on success
573 static rpmRC runTriggers(rpmpsm psm)
575 const rpmts ts = psm->ts;
577 const char * N = NULL;
580 if (psm->te) /* XXX can't happen */
582 if (N) /* XXX can't happen */
583 numPackage = rpmdbCountPackages(rpmtsGetRdb(ts), N)
584 + psm->countCorrection;
586 return RPMRC_NOTFOUND;
589 Header h = rpmteHeader(psm->te);
590 rpmdbMatchIterator mi;
591 int countCorrection = psm->countCorrection;
593 psm->countCorrection = 0;
594 mi = rpmtsInitIterator(ts, RPMDBI_TRIGGERNAME, N, 0);
595 while((triggeredH = rpmdbNextIterator(mi)) != NULL)
596 nerrors += handleOneTrigger(psm, h, triggeredH, numPackage, NULL);
597 mi = rpmdbFreeIterator(mi);
598 psm->countCorrection = countCorrection;
602 return (nerrors == 0) ? RPMRC_OK : RPMRC_FAIL;
606 * Run triggers from this header that are fired by headers in the database.
607 * @param psm package state machine data
608 * @return 0 on success
610 static rpmRC runImmedTriggers(rpmpsm psm)
612 const rpmts ts = psm->ts;
613 unsigned char * triggersRun;
614 struct rpmtd_s tnames, tindexes;
615 Header h = rpmteHeader(psm->te);
618 if (!(headerGet(h, RPMTAG_TRIGGERNAME, &tnames, HEADERGET_MINMEM) &&
619 headerGet(h, RPMTAG_TRIGGERINDEX, &tindexes, HEADERGET_MINMEM))) {
623 triggersRun = xcalloc(rpmtdCount(&tindexes), sizeof(*triggersRun));
624 { Header sourceH = NULL;
625 const char *trigName;
626 rpm_count_t *triggerIndices = tindexes.data;
628 while ((trigName = rpmtdNextString(&tnames))) {
629 rpmdbMatchIterator mi;
630 int i = rpmtdGetIndex(&tnames);
632 if (triggersRun[triggerIndices[i]] != 0) continue;
634 mi = rpmtsInitIterator(ts, RPMDBI_NAME, trigName, 0);
636 while((sourceH = rpmdbNextIterator(mi)) != NULL) {
637 nerrors += handleOneTrigger(psm, sourceH, h,
638 rpmdbGetIteratorCount(mi),
642 mi = rpmdbFreeIterator(mi);
645 rpmtdFreeData(&tnames);
646 rpmtdFreeData(&tindexes);
651 return (nerrors == 0) ? RPMRC_OK : RPMRC_FAIL;
654 static rpmpsm rpmpsmFree(rpmpsm psm)
659 psm->fi = rpmfiFree(psm->fi);
661 psm->te = rpmteFree(psm->te);
665 psm->ts = rpmtsFree(psm->ts);
667 memset(psm, 0, sizeof(*psm)); /* XXX trash and burn */
673 static rpmpsm rpmpsmNew(rpmts ts, rpmte te)
675 rpmpsm psm = xcalloc(1, sizeof(*psm));
677 if (ts) psm->ts = rpmtsLink(ts);
680 psm->te = rpmteLink(te, RPMDBG_M("rpmpsmNew"));Â
684 psm->fi = rpmfiLink(rpmteFI(te));
690 static rpmRC rpmpsmNext(rpmpsm psm, pkgStage nstage)
692 psm->nstage = nstage;
693 return rpmpsmStage(psm, psm->nstage);
696 static rpmRC rpmpsmStage(rpmpsm psm, pkgStage stage)
698 const rpmts ts = psm->ts;
699 rpm_color_t tscolor = rpmtsColor(ts);
709 rpmlog(RPMLOG_DEBUG, "%s: %s has %d files\n",
710 psm->goalName, rpmteNEVR(psm->te), rpmfiFC(fi));
713 * When we run scripts, we pass an argument which is the number of
714 * versions of this package that will be installed when we are
717 psm->npkgs_installed = rpmdbCountPackages(rpmtsGetRdb(ts), rpmteN(psm->te));
718 if (psm->npkgs_installed < 0) {
723 if (psm->goal == PKG_INSTALL) {
724 rpmdbMatchIterator mi;
727 psm->scriptArg = psm->npkgs_installed + 1;
729 mi = rpmtsInitIterator(ts, RPMDBI_NAME, rpmteN(psm->te), 0);
730 xx = rpmdbSetIteratorRE(mi, RPMTAG_EPOCH, RPMMIRE_STRCMP,
732 xx = rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_STRCMP,
734 xx = rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_STRCMP,
737 xx = rpmdbSetIteratorRE(mi, RPMTAG_ARCH, RPMMIRE_STRCMP,
739 xx = rpmdbSetIteratorRE(mi, RPMTAG_OS, RPMMIRE_STRCMP,
743 while ((oh = rpmdbNextIterator(mi)) != NULL) {
744 rpmteSetDBInstance(psm->te, rpmdbGetIteratorOffset(mi));
748 mi = rpmdbFreeIterator(mi);
751 if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB) break;
753 if (rpmfiFC(fi) > 0) {
754 struct rpmtd_s filenames;
755 rpmTag ftag = RPMTAG_FILENAMES;
756 Header h = rpmteHeader(psm->te);
758 if (headerIsEntry(h, RPMTAG_ORIGBASENAMES)) {
759 ftag = RPMTAG_ORIGFILENAMES;
761 headerGet(h, ftag, &filenames, HEADERGET_EXT);
762 fi->apath = filenames.data; /* Ick.. */
766 if (psm->goal == PKG_ERASE) {
767 psm->scriptArg = psm->npkgs_installed - 1;
771 if (psm->goal == PKG_INSTALL) {
772 psm->scriptTag = RPMTAG_PREIN;
773 psm->sense = RPMSENSE_TRIGGERPREIN;
774 psm->countCorrection = 0; /* XXX is this correct?!? */
776 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERPREIN)) {
777 /* Run triggers in other package(s) this package sets off. */
778 rc = rpmpsmNext(psm, PSM_TRIGGERS);
781 /* Run triggers in this package other package(s) set off. */
782 rc = rpmpsmNext(psm, PSM_IMMED_TRIGGERS);
786 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPRE)) {
787 rc = rpmpsmNext(psm, PSM_SCRIPT);
792 if (psm->goal == PKG_ERASE) {
793 psm->scriptTag = RPMTAG_PREUN;
794 psm->sense = RPMSENSE_TRIGGERUN;
795 psm->countCorrection = -1;
797 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERUN)) {
798 /* Run triggers in this package other package(s) set off. */
799 rc = rpmpsmNext(psm, PSM_IMMED_TRIGGERS);
802 /* Run triggers in other package(s) this package sets off. */
803 rc = rpmpsmNext(psm, PSM_TRIGGERS);
807 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPREUN))
808 rc = rpmpsmNext(psm, PSM_SCRIPT);
812 if (psm->goal == PKG_INSTALL) {
815 if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB) break;
817 /* XXX Synthesize callbacks for packages with no files. */
818 if (rpmfiFC(fi) <= 0) {
820 ptr = rpmtsNotify(ts, psm->te, RPMCALLBACK_INST_START, 0, 100);
821 ptr = rpmtsNotify(ts, psm->te, RPMCALLBACK_INST_PROGRESS, 100, 100);
825 payload = rpmtePayload(psm->te);
826 if (payload == NULL) {
831 rc = fsmSetup(rpmfiFSM(fi), FSM_PKGINSTALL, ts, psm->te, fi,
832 payload, NULL, &psm->failedFile);
833 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_UNCOMPRESS),
834 fdOp(payload, FDSTAT_READ));
835 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DIGEST),
836 fdOp(payload, FDSTAT_DIGEST));
837 xx = fsmTeardown(rpmfiFSM(fi));
839 saveerrno = errno; /* XXX FIXME: Fclose with libio destroys errno */
840 xx = Fclose(payload);
841 errno = saveerrno; /* XXX FIXME: Fclose with libio destroys errno */
844 rc = rpmpsmNext(psm, PSM_COMMIT);
846 /* XXX make sure progress is closed out */
847 psm->what = RPMCALLBACK_INST_PROGRESS;
848 psm->amount = (fi->archiveSize ? fi->archiveSize : 100);
849 psm->total = psm->amount;
850 xx = rpmpsmNext(psm, PSM_NOTIFY);
854 _("unpacking of archive failed%s%s: %s\n"),
855 (psm->failedFile != NULL ? _(" on file ") : ""),
856 (psm->failedFile != NULL ? psm->failedFile : ""),
860 /* XXX notify callback on error. */
861 psm->what = RPMCALLBACK_UNPACK_ERROR;
864 xx = rpmpsmNext(psm, PSM_NOTIFY);
869 if (psm->goal == PKG_ERASE) {
870 int fc = rpmfiFC(fi);
872 if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB) break;
873 if (rpmtsFlags(ts) & RPMTRANS_FLAG_APPLYONLY) break;
875 /* XXX Synthesize callbacks for packages with no files. */
876 if (rpmfiFC(fi) <= 0) {
878 ptr = rpmtsNotify(ts, psm->te, RPMCALLBACK_UNINST_START, 0, 100);
879 ptr = rpmtsNotify(ts, psm->te, RPMCALLBACK_UNINST_STOP, 0, 100);
883 psm->what = RPMCALLBACK_UNINST_START;
884 psm->amount = fc; /* XXX W2DO? looks wrong. */
886 xx = rpmpsmNext(psm, PSM_NOTIFY);
888 rc = fsmSetup(rpmfiFSM(fi), FSM_PKGERASE, ts, psm->te, fi,
889 NULL, NULL, &psm->failedFile);
890 xx = fsmTeardown(rpmfiFSM(fi));
892 psm->what = RPMCALLBACK_UNINST_STOP;
893 psm->amount = 0; /* XXX W2DO? looks wrong. */
895 xx = rpmpsmNext(psm, PSM_NOTIFY);
900 if (psm->goal == PKG_INSTALL) {
901 rpm_time_t installTime = (rpm_time_t) time(NULL);
902 rpmfs fs = rpmteGetFileStates(psm->te);
903 rpm_count_t fc = rpmfsFC(fs);
904 rpm_fstate_t * fileStates = rpmfsGetStates(fs);
905 Header h = rpmteHeader(psm->te);
907 if (fileStates != NULL && fc > 0) {
908 headerPutChar(h, RPMTAG_FILESTATES, fileStates, fc);
911 headerPutUint32(h, RPMTAG_INSTALLTIME, &installTime, 1);
912 headerPutUint32(h, RPMTAG_INSTALLCOLOR, &tscolor, 1);
916 * If this package has already been installed, remove it from
917 * the database before adding the new one.
919 if (rpmteDBInstance(psm->te) &&
920 !(rpmtsFlags(ts) & RPMTRANS_FLAG_APPLYONLY)) {
921 rc = rpmpsmNext(psm, PSM_RPMDB_REMOVE);
925 rc = rpmpsmNext(psm, PSM_RPMDB_ADD);
928 psm->scriptTag = RPMTAG_POSTIN;
929 psm->sense = RPMSENSE_TRIGGERIN;
930 psm->countCorrection = 0;
932 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPOST)) {
933 rc = rpmpsmNext(psm, PSM_SCRIPT);
936 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERIN)) {
937 /* Run triggers in other package(s) this package sets off. */
938 rc = rpmpsmNext(psm, PSM_TRIGGERS);
941 /* Run triggers in this package other package(s) set off. */
942 rc = rpmpsmNext(psm, PSM_IMMED_TRIGGERS);
946 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_APPLYONLY))
947 rc = markReplacedFiles(psm);
950 if (psm->goal == PKG_ERASE) {
952 psm->scriptTag = RPMTAG_POSTUN;
953 psm->sense = RPMSENSE_TRIGGERPOSTUN;
954 psm->countCorrection = -1;
956 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPOSTUN)) {
957 rc = rpmpsmNext(psm, PSM_SCRIPT);
961 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERPOSTUN)) {
962 /* Run triggers in other package(s) this package sets off. */
963 rc = rpmpsmNext(psm, PSM_TRIGGERS);
967 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_APPLYONLY))
968 rc = rpmpsmNext(psm, PSM_RPMDB_REMOVE);
977 _("%s failed on file %s: %s\n"),
978 psm->goalName, psm->failedFile, cpioStrerror(rc));
980 rpmlog(RPMLOG_ERR, _("%s failed: %s\n"),
981 psm->goalName, cpioStrerror(rc));
983 /* XXX notify callback on error. */
984 psm->what = RPMCALLBACK_CPIO_ERROR;
987 xx = rpmpsmNext(psm, PSM_NOTIFY);
990 psm->failedFile = _free(psm->failedFile);
992 fi->apath = _free(fi->apath);
1002 /* FIX: psm->te may be NULL */
1003 ptr = rpmtsNotify(ts, psm->te, psm->what, psm->amount, psm->total);
1008 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_PKGCOMMIT)) break;
1009 if (rpmtsFlags(ts) & RPMTRANS_FLAG_APPLYONLY) break;
1011 rc = fsmSetup(rpmfiFSM(fi), FSM_PKGCOMMIT, ts, psm->te, fi,
1012 NULL, NULL, &psm->failedFile);
1013 xx = fsmTeardown(rpmfiFSM(fi));
1016 case PSM_SCRIPT: /* Run current package scriptlets. */
1017 rc = runInstScript(psm);
1020 /* Run triggers in other package(s) this package sets off. */
1021 rc = runTriggers(psm);
1023 case PSM_IMMED_TRIGGERS:
1024 /* Run triggers in this package other package(s) set off. */
1025 rc = runImmedTriggers(psm);
1028 case PSM_RPMDB_ADD: {
1029 Header h = rpmteHeader(psm->te);
1031 if (!headerIsEntry(h, RPMTAG_INSTALLTID)) {
1032 rpm_tid_t tid = rpmtsGetTid(ts);
1033 if (tid != 0 && tid != (rpm_tid_t)-1)
1034 headerPutUint32(h, RPMTAG_INSTALLTID, &tid, 1);
1037 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DBADD), 0);
1038 rc = (rpmdbAdd(rpmtsGetRdb(ts), h) == 0) ? RPMRC_OK : RPMRC_FAIL;
1039 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DBADD), 0);
1042 rpmteSetDBInstance(psm->te, headerGetInstance(h));
1046 case PSM_RPMDB_REMOVE:
1047 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DBREMOVE), 0);
1048 rc = (rpmdbRemove(rpmtsGetRdb(ts), rpmteDBInstance(psm->te)) == 0) ?
1049 RPMRC_OK : RPMRC_FAIL;
1050 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DBREMOVE), 0);
1052 rpmteSetDBInstance(psm->te, 0);
1062 static const char * pkgGoalString(pkgGoal goal)
1065 case PKG_INSTALL: return " install";
1066 case PKG_ERASE: return " erase";
1067 case PKG_VERIFY: return " verify";
1068 case PKG_PRETRANS: return " pretrans";
1069 case PKG_POSTTRANS: return "posttrans";
1070 default: return "unknown";
1074 rpmRC rpmpsmRun(rpmts ts, rpmte te, pkgGoal goal)
1077 rpmRC rc = RPMRC_FAIL;
1079 /* Psm can't fail in test mode, just return early */
1080 if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)
1083 psm = rpmpsmNew(ts, te);
1084 if (rpmChrootIn() == 0) {
1087 psm->goalName = pkgGoalString(goal);
1092 op = (goal == PKG_INSTALL) ? RPMTS_OP_INSTALL : RPMTS_OP_ERASE;
1093 rpmswEnter(rpmtsOp(psm->ts, op), 0);
1095 rc = rpmpsmNext(psm, PSM_INIT);
1096 if (!rc) rc = rpmpsmNext(psm, PSM_PRE);
1097 if (!rc) rc = rpmpsmNext(psm, PSM_PROCESS);
1098 if (!rc) rc = rpmpsmNext(psm, PSM_POST);
1099 (void) rpmpsmNext(psm, PSM_FINI);
1101 rpmswExit(rpmtsOp(psm->ts, op), 0);
1106 psm->scriptTag = goal;
1107 rc = rpmpsmStage(psm, PSM_SCRIPT);
1112 /* XXX an error here would require a full abort */
1113 (void) rpmChrootOut();