summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile.am4
-rw-r--r--lib/psm.c605
-rw-r--r--lib/psm.h48
-rw-r--r--lib/scriptlet.c474
-rw-r--r--lib/scriptlet.h41
-rw-r--r--lib/verify.c2
6 files changed, 546 insertions, 628 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 5c6d58d2e..83faf1aac 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -13,7 +13,7 @@ pkginc_HEADERS = \
noinst_HEADERS = \
cpio.h depends.h falloc.h fprint.h fsm.h hash.h \
md5.h psm.h \
- rpmdb.h rpmlead.h scriptlet.h signature.h
+ rpmdb.h rpmlead.h signature.h
mylibpaths = -L$(top_builddir)/lib/.libs -L$(top_builddir)/rpmio/.libs \
-L$(top_builddir)/popt/.libs
@@ -27,7 +27,7 @@ librpm_la_SOURCES = \
md5.c md5sum.c misc.c package.c problems.c \
poptBT.c poptQV.c psm.c query.c \
rpmchecksig.c rpmdb.c rpminstall.c \
- rpmlead.c rpmlibprov.c rpmrc.c scriptlet.c signature.c stringbuf.c \
+ rpmlead.c rpmlibprov.c rpmrc.c signature.c stringbuf.c \
tagName.c tagtable.c transaction.c verify.c
librpm_la_LDFLAGS = @libdb3@ @libdb2@ @libdb1@
librpm_la_LIBADD = $(DBLIBOBJS)
diff --git a/lib/psm.c b/lib/psm.c
index 162e41b24..71a10e393 100644
--- a/lib/psm.c
+++ b/lib/psm.c
@@ -867,135 +867,546 @@ exit:
return rc;
}
+static char * SCRIPT_PATH = "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin";
+
+/**
+ * Return scriptlet name from tag.
+ * @param tag scriptlet tag
+ * @return name of scriptlet
+ */
+static /*@observer@*/ const char * const tag2sln(int tag)
+{
+ switch (tag) {
+ case RPMTAG_PREIN: return "%pre";
+ case RPMTAG_POSTIN: return "%post";
+ case RPMTAG_PREUN: return "%preun";
+ case RPMTAG_POSTUN: return "%postun";
+ case RPMTAG_VERIFYSCRIPT: return "%verify";
+ }
+ return "%unknownscript";
+}
+
/**
- * Enter and leave a chroot.
+ * Run scriptlet with args.
+ *
+ * Run a script with an interpreter. If the interpreter is not specified,
+ * /bin/sh will be used. If the interpreter is /bin/sh, then the args from
+ * the header will be ignored, passing instead arg1 and arg2.
+ *
* @param psm package state machine data
- * @return 0 on sucess or not performed, chroot(2) rc otherwise
+ * @param h header
+ * @param sln name of scriptlet section
+ * @param progArgc no. of args from header
+ * @param progArgv args from header, progArgv[0] is the interpreter to use
+ * @param script scriptlet from header
+ * @param arg1 no. instances of package installed after scriptlet exec
+ * (-1 is no arg)
+ * @param arg2 ditto, but for the target package
+ * @return 0 on success, 1 on error
*/
-static int psmChroot(PSM_t psm, int enter)
+static int runScript(PSM_t psm, Header h,
+ const char * sln,
+ int progArgc, const char ** progArgv,
+ const char * script, int arg1, int arg2)
{
const rpmTransactionSet ts = psm->ts;
TFI_t fi = psm->fi;
+ HGE_t hge = fi->hge;
+ HFD_t hfd = fi->hfd;
+ const char ** argv = NULL;
+ int argc = 0;
+ const char ** prefixes = NULL;
+ int numPrefixes;
+ int_32 ipt;
+ const char * oldPrefix;
+ int maxPrefixLength;
+ int len;
+ char * prefixBuf = NULL;
+ pid_t child;
+ int status = 0;
+ const char * fn = NULL;
+ int i;
+ int freePrefixes = 0;
+ FD_t out;
int rc = 0;
+ const char *n, *v, *r;
- if (enter) {
- /* Change root directory if requested and not already done. */
- if (ts->rootDir && !ts->chrootDone && !fi->chrootDone) {
- static int _loaded = 0;
+ if (!progArgv && !script)
+ return 0;
- /*
- * This loads all of the name services libraries, in case we
- * don't have access to them in the chroot().
- */
- if (!_loaded) {
- (void)getpwnam("root");
- endpwent();
- _loaded++;
+ if (!progArgv) {
+ argv = alloca(5 * sizeof(char *));
+ argv[0] = "/bin/sh";
+ argc = 1;
+ } else {
+ argv = alloca((progArgc + 4) * sizeof(char *));
+ memcpy(argv, progArgv, progArgc * sizeof(char *));
+ argc = progArgc;
+ }
+
+ headerNVR(h, &n, &v, &r);
+ if (hge(h, RPMTAG_INSTPREFIXES, &ipt, (void **) &prefixes, &numPrefixes)) {
+ freePrefixes = 1;
+ } else if (hge(h, RPMTAG_INSTALLPREFIX, NULL, (void **) &oldPrefix, NULL)) {
+ prefixes = &oldPrefix;
+ numPrefixes = 1;
+ } else {
+ numPrefixes = 0;
+ }
+
+ maxPrefixLength = 0;
+ for (i = 0; i < numPrefixes; i++) {
+ len = strlen(prefixes[i]);
+ if (len > maxPrefixLength) maxPrefixLength = len;
+ }
+ prefixBuf = alloca(maxPrefixLength + 50);
+
+ if (script) {
+ FD_t fd;
+ if (makeTempFile((!ts->chrootDone ? ts->rootDir : "/"), &fn, &fd)) {
+ if (freePrefixes) free(prefixes);
+ return 1;
+ }
+
+ if (rpmIsDebug() &&
+ (!strcmp(argv[0], "/bin/sh") || !strcmp(argv[0], "/bin/bash")))
+ (void)Fwrite("set -x\n", sizeof(char), 7, fd);
+
+ (void)Fwrite(script, sizeof(script[0]), strlen(script), fd);
+ Fclose(fd);
+
+ { const char * sn = fn;
+ if (!ts->chrootDone &&
+ !(ts->rootDir[0] == '/' && ts->rootDir[1] == '\0'))
+ {
+ sn += strlen(ts->rootDir)-1;
+ }
+ argv[argc++] = sn;
+ }
+
+ if (arg1 >= 0) {
+ char *av = alloca(20);
+ sprintf(av, "%d", arg1);
+ argv[argc++] = av;
+ }
+ if (arg2 >= 0) {
+ char *av = alloca(20);
+ sprintf(av, "%d", arg2);
+ argv[argc++] = av;
+ }
+ }
+
+ argv[argc] = NULL;
+
+ if (ts->scriptFd != NULL) {
+ if (rpmIsVerbose()) {
+ out = fdDup(Fileno(ts->scriptFd));
+ } else {
+ out = Fopen("/dev/null", "w.fdio");
+ if (Ferror(out)) {
+ out = fdDup(Fileno(ts->scriptFd));
+ }
+ }
+ } else {
+ out = fdDup(STDOUT_FILENO);
+ out = fdLink(out, "runScript persist");
+ }
+
+ if (!(child = fork())) {
+ const char * rootDir;
+ int pipes[2];
+
+ pipes[0] = pipes[1] = 0;
+ /* make stdin inaccessible */
+ pipe(pipes);
+ close(pipes[1]);
+ dup2(pipes[0], STDIN_FILENO);
+ close(pipes[0]);
+
+ if (ts->scriptFd != NULL) {
+ if (Fileno(ts->scriptFd) != STDERR_FILENO)
+ dup2(Fileno(ts->scriptFd), STDERR_FILENO);
+ if (Fileno(out) != STDOUT_FILENO)
+ dup2(Fileno(out), STDOUT_FILENO);
+ /* make sure we don't close stdin/stderr/stdout by mistake! */
+ if (Fileno(out) > STDERR_FILENO && Fileno(out) != Fileno(ts->scriptFd)) {
+ Fclose (out);
+ }
+ if (Fileno(ts->scriptFd) > STDERR_FILENO) {
+ Fclose (ts->scriptFd);
+ }
+ }
+
+ { const char *ipath = rpmExpand("PATH=%{_install_script_path}", NULL);
+ const char *path = SCRIPT_PATH;
+
+ if (ipath && ipath[5] != '%')
+ path = ipath;
+ doputenv(path);
+ if (ipath) free((void *)ipath);
+ }
+
+ for (i = 0; i < numPrefixes; i++) {
+ sprintf(prefixBuf, "RPM_INSTALL_PREFIX%d=%s", i, prefixes[i]);
+ doputenv(prefixBuf);
+
+ /* backwards compatibility */
+ if (i == 0) {
+ sprintf(prefixBuf, "RPM_INSTALL_PREFIX=%s", prefixes[i]);
+ doputenv(prefixBuf);
}
+ }
+ rootDir = ts->rootDir;
+ switch(urlIsURL(rootDir)) {
+ case URL_IS_PATH:
+ rootDir += sizeof("file://") - 1;
+ rootDir = strchr(rootDir, '/');
+ /*@fallthrough@*/
+ case URL_IS_UNKNOWN:
+ if (!ts->chrootDone && !(rootDir[0] == '/' && rootDir[1] == '\0')) {
+ /*@-unrecog@*/ chroot(rootDir); /*@=unrecog@*/
+ }
chdir("/");
- /*@-unrecog@*/
- rc = chroot(ts->rootDir);
- /*@=unrecog@*/
- fi->chrootDone = ts->chrootDone = 1;
+ execv(argv[0], (char *const *)argv);
+ break;
+ default:
+ break;
}
+
+ _exit(-1);
+ /*@notreached@*/
+ }
+
+ if (waitpid(child, &status, 0) < 0) {
+ rpmError(RPMERR_SCRIPT,
+ _("execution of %s scriptlet from %s-%s-%s failed, waitpid returned %s\n"),
+ sln, n, v, r, strerror (errno));
+ /* XXX what to do here? */
+ rc = 0;
} else {
- /* Restore root directory if changed. */
- if (fi->chrootDone) {
- /*@-unrecog@*/
- rc = chroot(".");
- /*@=unrecog@*/
- fi->chrootDone = ts->chrootDone = 0;
- chdir(ts->currDir);
+ if (!WIFEXITED(status) || WEXITSTATUS(status)) {
+ rpmError(RPMERR_SCRIPT,
+ _("execution of %s scriptlet from %s-%s-%s failed, exit status %d\n"),
+ sln, n, v, r, WEXITSTATUS(status));
+ rc = 1;
+ }
+ }
+
+ if (freePrefixes) prefixes = hfd(prefixes, ipt);
+
+ Fclose(out); /* XXX dup'd STDOUT_FILENO */
+
+ if (script) {
+ if (!rpmIsDebug()) unlink(fn);
+ free((void *)fn);
+ }
+
+ return rc;
+}
+
+/**
+ * Retrieve and run scriptlet from header.
+ * @param psm package state machine data
+ * @return 0 on success
+ */
+static int runInstScript(PSM_t psm)
+{
+ const rpmTransactionSet ts = psm->ts;
+ TFI_t fi = psm->fi;
+ HGE_t hge = fi->hge;
+ HFD_t hfd = fi->hfd;
+ void ** programArgv;
+ int programArgc;
+ const char ** argv;
+ int_32 ptt, stt;
+ const char * script;
+ int rc;
+
+ if (ts->transFlags & RPMTRANS_FLAG_NOSCRIPTS)
+ return 0;
+
+ /*
+ * headerGetEntry() sets the data pointer to NULL if the entry does
+ * not exist.
+ */
+ hge(fi->h, psm->progTag, &ptt, (void **) &programArgv, &programArgc);
+ hge(fi->h, psm->scriptTag, &stt, (void **) &script, NULL);
+
+ if (programArgv && ptt == RPM_STRING_TYPE) {
+ argv = alloca(sizeof(char *));
+ *argv = (const char *) programArgv;
+ } else {
+ argv = (const char **) programArgv;
+ }
+
+ rc = runScript(psm, fi->h, tag2sln(psm->scriptTag), programArgc, argv,
+ script, psm->scriptArg, -1);
+ programArgv = hfd(programArgv, ptt);
+ script = hfd(script, stt);
+ return rc;
+}
+
+/**
+ * @param psm package state machine data
+ * @param sourceH
+ * @param triggeredH
+ * @param arg2
+ * @param triggersAlreadyRun
+ * @return
+ */
+static int handleOneTrigger(PSM_t psm, Header sourceH, Header triggeredH,
+ int arg2, char * triggersAlreadyRun)
+{
+ const rpmTransactionSet ts = psm->ts;
+ TFI_t fi = psm->fi;
+ HGE_t hge = fi->hge;
+ HFD_t hfd = fi->hfd;
+ const char ** triggerNames;
+ const char ** triggerEVR;
+ const char ** triggerScripts;
+ const char ** triggerProgs;
+ int_32 * triggerFlags;
+ int_32 * triggerIndices;
+ int_32 tnt, tvt, tft;
+ const char * triggerPackageName;
+ const char * sourceName;
+ int numTriggers;
+ int rc = 0;
+ int i;
+ int skip;
+
+ if (!hge(triggeredH, RPMTAG_TRIGGERNAME, &tnt,
+ (void **) &triggerNames, &numTriggers))
+ return 0;
+
+ headerNVR(sourceH, &sourceName, NULL, NULL);
+
+ hge(triggeredH, RPMTAG_TRIGGERFLAGS, &tft, (void **) &triggerFlags, NULL);
+ hge(triggeredH, RPMTAG_TRIGGERVERSION, &tvt, (void **) &triggerEVR, NULL);
+
+ for (i = 0; i < numTriggers; i++) {
+ int_32 tit, tst, tpt;
+
+ if (!(triggerFlags[i] & psm->sense)) continue;
+ if (strcmp(triggerNames[i], sourceName)) continue;
+
+ /*
+ * For some reason, the TRIGGERVERSION stuff includes the name of
+ * the package which the trigger is based on. We need to skip
+ * over that here. I suspect that we'll change our minds on this
+ * and remove that, so I'm going to just 'do the right thing'.
+ */
+ skip = strlen(triggerNames[i]);
+ if (!strncmp(triggerEVR[i], triggerNames[i], skip) &&
+ (triggerEVR[i][skip] == '-'))
+ skip++;
+ else
+ skip = 0;
+
+ if (!headerMatchesDepFlags(sourceH, triggerNames[i],
+ triggerEVR[i] + skip, triggerFlags[i]))
+ continue;
+
+ hge(triggeredH, RPMTAG_TRIGGERINDEX, &tit,
+ (void **) &triggerIndices, NULL);
+ hge(triggeredH, RPMTAG_TRIGGERSCRIPTS, &tst,
+ (void **) &triggerScripts, NULL);
+ hge(triggeredH, RPMTAG_TRIGGERSCRIPTPROG, &tpt,
+ (void **) &triggerProgs, NULL);
+
+ headerNVR(triggeredH, &triggerPackageName, NULL, NULL);
+
+ { int arg1;
+ int index;
+
+ arg1 = rpmdbCountPackages(ts->rpmdb, triggerPackageName);
+ if (arg1 < 0) {
+ rc = 1; /* XXX W2DO? same as "execution of script failed" */
+ } else {
+ arg1 += psm->countCorrection;
+ index = triggerIndices[i];
+ if (!triggersAlreadyRun || !triggersAlreadyRun[index]) {
+ rc = runScript(psm, triggeredH, "%trigger", 1,
+ triggerProgs + index, triggerScripts[index],
+ arg1, arg2);
+ if (triggersAlreadyRun) triggersAlreadyRun[index] = 1;
+ }
+ }
+ }
+
+ triggerIndices = hfd(triggerIndices, tit);
+ triggerScripts = hfd(triggerScripts, tst);
+ triggerProgs = hfd(triggerProgs, tpt);
+
+ /*
+ * Each target/source header pair can only result in a single
+ * script being run.
+ */
+ break;
+ }
+
+ triggerNames = hfd(triggerNames, tnt);
+ triggerFlags = hfd(triggerFlags, tft);
+ triggerEVR = hfd(triggerEVR, tvt);
+
+ return rc;
+}
+
+/**
+ * Run trigger scripts in the database that are fired by this header.
+ * @param psm package state machine data
+ * @return 0 on success, 1 on error
+ */
+static int runTriggers(PSM_t psm)
+{
+ const rpmTransactionSet ts = psm->ts;
+ TFI_t fi = psm->fi;
+ int numPackage;
+ int rc = 0;
+
+ numPackage = rpmdbCountPackages(ts->rpmdb, fi->name) + psm->countCorrection;
+ if (numPackage < 0)
+ return 1;
+
+ { Header triggeredH;
+ rpmdbMatchIterator mi;
+ int countCorrection = psm->countCorrection;
+
+ psm->countCorrection = 0;
+ mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_TRIGGERNAME, fi->name, 0);
+ while((triggeredH = rpmdbNextIterator(mi)) != NULL) {
+ rc |= handleOneTrigger(psm, fi->h, triggeredH, numPackage, NULL);
+ }
+
+ rpmdbFreeIterator(mi);
+ psm->countCorrection = countCorrection;
+ }
+
+ return rc;
+}
+
+/**
+ * Run triggers from this header that are fired by headers in the database.
+ * @param psm package state machine data
+ * @return 0 on success, 1 on error
+ */
+static int runImmedTriggers(PSM_t psm)
+{
+ const rpmTransactionSet ts = psm->ts;
+ TFI_t fi = psm->fi;
+ HGE_t hge = fi->hge;
+ HFD_t hfd = fi->hfd;
+ const char ** triggerNames;
+ int numTriggers;
+ int_32 * triggerIndices;
+ int_32 tnt, tit;
+ int numTriggerIndices;
+ char * triggersRun;
+ int rc = 0;
+
+ if (!hge(fi->h, RPMTAG_TRIGGERNAME, &tnt,
+ (void **) &triggerNames, &numTriggers))
+ return 0;
+
+ hge(fi->h, RPMTAG_TRIGGERINDEX, &tit, (void **) &triggerIndices,
+ &numTriggerIndices);
+ triggersRun = alloca(sizeof(*triggersRun) * numTriggerIndices);
+ memset(triggersRun, 0, sizeof(*triggersRun) * numTriggerIndices);
+
+ { Header sourceH = NULL;
+ int i;
+
+ for (i = 0; i < numTriggers; i++) {
+ rpmdbMatchIterator mi;
+
+ if (triggersRun[triggerIndices[i]]) continue;
+
+ mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_NAME, triggerNames[i], 0);
+
+ while((sourceH = rpmdbNextIterator(mi)) != NULL) {
+ rc |= handleOneTrigger(psm, sourceH, fi->h,
+ rpmdbGetIteratorCount(mi),
+ triggersRun);
+ }
+
+ rpmdbFreeIterator(mi);
}
}
+ triggerIndices = hfd(triggerNames, tit);
+ triggerNames = hfd(triggerNames, tnt);
return rc;
}
-int psmStage(PSM_t psm, fileStage stage)
+int psmStage(PSM_t psm, pkgStage stage)
{
- const char * const cur = fileStageString(stage);
+ const rpmTransactionSet ts = psm->ts;
+ TFI_t fi = psm->fi;
int rc = psm->rc;
int i;
switch (stage) {
- case FSM_UNKNOWN:
- break;
- case FSM_PKGINSTALL:
- break;
- case FSM_PKGERASE:
- break;
- case FSM_PKGSAVE:
- break;
- case FSM_PKGCOMMIT:
- break;
- case FSM_PKGBUILD:
- break;
- case FSM_CREATE:
- break;
- case FSM_INIT:
- break;
- case FSM_PRE:
+ case PSM_UNKNOWN:
break;
- case FSM_MAP:
+ case PSM_INIT:
break;
- case FSM_MKDIRS:
+ case PSM_PRE:
break;
- case FSM_RMDIRS:
+ case PSM_PROCESS:
break;
- case FSM_PROCESS:
+ case PSM_POST:
break;
- case FSM_POST:
+ case PSM_UNDO:
break;
- case FSM_MKLINKS:
+ case PSM_FINI:
break;
- case FSM_NOTIFY:
+ case PSM_NOTIFY:
break;
- case FSM_UNDO:
+ case PSM_COMMIT:
break;
- case FSM_FINI:
+ case PSM_CREATE:
break;
- case FSM_COMMIT:
+ case PSM_DESTROY:
break;
- case FSM_DESTROY:
+
+ case PSM_CHROOT_IN:
+ /* Change root directory if requested and not already done. */
+ if (ts->rootDir && !ts->chrootDone && !psm->chrootDone) {
+ static int _loaded = 0;
+
+ /*
+ * This loads all of the name services libraries, in case we
+ * don't have access to them in the chroot().
+ */
+ if (!_loaded) {
+ (void)getpwnam("root");
+ endpwent();
+ _loaded++;
+ }
+
+ chdir("/");
+ /*@-unrecog@*/
+ rc = chroot(ts->rootDir);
+ /*@=unrecog@*/
+ psm->chrootDone = ts->chrootDone = 1;
+ }
break;
- case FSM_VERIFY:
+ case PSM_CHROOT_OUT:
+ /* Restore root directory if changed. */
+ if (psm->chrootDone) {
+ /*@-unrecog@*/
+ rc = chroot(".");
+ /*@=unrecog@*/
+ psm->chrootDone = ts->chrootDone = 0;
+ chdir(ts->currDir);
+ }
break;
-
- case FSM_UNLINK:
- case FSM_RENAME:
- case FSM_MKDIR:
- case FSM_RMDIR:
- case FSM_CHOWN:
- case FSM_LCHOWN:
- case FSM_CHMOD:
- case FSM_UTIME:
- case FSM_SYMLINK:
- case FSM_LINK:
- case FSM_MKFIFO:
- case FSM_MKNOD:
- case FSM_LSTAT:
- case FSM_STAT:
- case FSM_READLINK:
+ case PSM_SCRIPT:
+ rc = runInstScript(psm);
break;
- case FSM_CHROOT:
+ case PSM_TRIGGER:
break;
- case FSM_NEXT:
- case FSM_EAT:
- case FSM_POS:
- case FSM_PAD:
- case FSM_TRAILER:
- case FSM_HREAD:
- case FSM_HWRITE:
- case FSM_DREAD:
- case FSM_DWRITE:
- case FSM_ROPEN:
- case FSM_READ:
- case FSM_RCLOSE:
- case FSM_WOPEN:
- case FSM_WRITE:
- case FSM_WCLOSE:
default:
break;
}
@@ -1096,7 +1507,7 @@ int installBinaryPackage(PSM_t psm)
}
/* Change root directory if requested and not already done. */
- (void) psmChroot(psm, 1);
+ (void) psmStage(psm, PSM_CHROOT_IN);
if (fi->fc > 0 && !(ts->transFlags & RPMTRANS_FLAG_JUSTDB)) {
@@ -1109,7 +1520,7 @@ int installBinaryPackage(PSM_t psm)
}
/* Restore root directory if changed. */
- (void) psmChroot(psm, 0);
+ (void) psmStage(psm, PSM_CHROOT_OUT);
if (fi->fc > 0 && fi->fstates) {
headerAddEntry(fi->h, RPMTAG_FILESTATES, RPM_CHAR_TYPE,
@@ -1183,7 +1594,7 @@ int installBinaryPackage(PSM_t psm)
exit:
/* Restore root directory if changed. */
- (void) psmChroot(psm, 0);
+ (void) psmStage(psm, PSM_CHROOT_OUT);
if (oldH)
headerFree(oldH);
@@ -1231,7 +1642,7 @@ assert(fi->type == TR_REMOVED);
}
/* Change root directory if requested and not already done. */
- (void) psmChroot(psm, 1);
+ (void) psmStage(psm, PSM_CHROOT_IN);
if (!(ts->transFlags & RPMTRANS_FLAG_NOTRIGGERS)) {
/* run triggers from this package which are keyed on installed
@@ -1245,8 +1656,6 @@ assert(fi->type == TR_REMOVED);
}
/* run triggers which are set off by the removal of this package */
- psm->sense = RPMSENSE_TRIGGERUN;
- psm->countCorrection = -1;
rc = runTriggers(psm);
if (rc) {
rc = 1;
@@ -1302,7 +1711,7 @@ assert(fi->type == TR_REMOVED);
exit:
/* Restore root directory if changed. */
- (void) psmChroot(psm, 0);
+ (void) psmStage(psm, PSM_CHROOT_OUT);
if (!rc && !(ts->transFlags & RPMTRANS_FLAG_TEST))
rpmdbRemove(ts->rpmdb, ts->id, fi->record);
@@ -1437,7 +1846,7 @@ assert(fi->type == TR_REMOVED);
if (rc) goto exit;
/* Change root directory if requested and not already done. */
- (void) psmChroot(psm, 1);
+ (void) psmStage(psm, PSM_CHROOT_IN);
/* Write the payload into the package. */
{ FD_t cfd;
@@ -1463,7 +1872,7 @@ assert(fi->type == TR_REMOVED);
exit:
/* Restore root directory if changed. */
- (void) psmChroot(psm, 0);
+ (void) psmStage(psm, PSM_CHROOT_OUT);
if (h) headerFree(h);
if (oh) headerFree(oh);
diff --git a/lib/psm.h b/lib/psm.h
index b44ba35cc..924c457c6 100644
--- a/lib/psm.h
+++ b/lib/psm.h
@@ -6,18 +6,10 @@
#include <rpmlib.h>
#include "depends.h"
-#include "scriptlet.h"
#include "fsm.h"
/**
*/
-typedef enum rollbackDir_e {
- ROLLBACK_SAVE = 1, /*!< Save files. */
- ROLLBACK_RESTORE = 2, /*!< Restore files. */
-} rollbackDir;
-
-/**
- */
struct sharedFile {
int mainFileNumber;
int secRecOffset;
@@ -72,7 +64,6 @@ struct transactionFileInfo_s {
int dnlmax; /*!< Length (in bytes) of longest dir name. */
int astriplen;
int striplen;
- int chrootDone;
unsigned int archiveSize;
mode_t dperms; /*!< Directory perms (0755) if not mapped. */
mode_t fperms; /*!< File perms (0644) if not mapped. */
@@ -97,16 +88,49 @@ struct transactionFileInfo_s {
/**
*/
+#define PSM_VERBOSE 0x8000
+#define PSM_INTERNAL 0x4000
+#define PSM_SYSCALL 0x2000
+#define PSM_DEAD 0x1000
+#define _fv(_a) ((_a) | PSM_VERBOSE)
+#define _fi(_a) ((_a) | PSM_INTERNAL)
+#define _fs(_a) ((_a) | (PSM_INTERNAL | PSM_SYSCALL))
+#define _fd(_a) ((_a) | (PSM_INTERNAL | PSM_DEAD))
+typedef enum pkgStage_e {
+ PSM_UNKNOWN = 0,
+ PSM_INIT = 1,
+ PSM_PRE = 2,
+ PSM_PROCESS = 3,
+ PSM_POST = 4,
+ PSM_UNDO = 5,
+ PSM_FINI = 6,
+ PSM_NOTIFY = 7,
+ PSM_COMMIT = 8,
+ PSM_CREATE = 9,
+ PSM_DESTROY = 10,
+ PSM_CHROOT_IN= 11,
+ PSM_CHROOT_OUT=12,
+ PSM_SCRIPT = 13,
+ PSM_TRIGGER = 14,
+} pkgStage;
+#undef _fv
+#undef _fi
+#undef _fs
+#undef _fd
+
+/**
+ */
struct psm_s {
rpmTransactionSet ts;
TFI_t fi;
- int scriptTag; /*!< Scriptlet tag. */
+ int scriptTag; /*!< Scriptlet data tag. */
int progTag; /*!< Scriptlet interpreter tag. */
int scriptArg; /*!< No. of installed instances. */
int sense; /*!< One of RPMSENSE_TRIGGER{IN,UN,POSTUN}. */
int countCorrection; /*!< 0 if installing, -1 if removing. */
+ int chrootDone; /*!< Was chroot(2) done by pkgStage? */
int rc;
- fileStage stage;
+ pkgStage stage;
};
#ifdef __cplusplus
@@ -167,7 +191,7 @@ int repackage(PSM_t psm)
/**
*/
-int psmStage(PSM_t psm, fileStage stage)
+int psmStage(PSM_t psm, pkgStage stage)
/*@modifies psm @*/;
#ifdef __cplusplus
diff --git a/lib/scriptlet.c b/lib/scriptlet.c
deleted file mode 100644
index 3ab047bcd..000000000
--- a/lib/scriptlet.c
+++ /dev/null
@@ -1,474 +0,0 @@
-/** \ingroup rpmtrans payload
- * \file lib/scriptlet.c
- */
-
-#include "system.h"
-
-#include <rpmlib.h>
-#include <rpmurl.h>
-#include <rpmmacro.h> /* XXX for rpmExpand */
-
-#include "depends.h" /* XXX for headerMatchesDepFlags */
-#include "psm.h"
-#include "scriptlet.h"
-#include "misc.h" /* XXX for makeTempFile, doputenv */
-#include "debug.h"
-
-/*@access Header @*/ /* XXX compared with NULL */
-/*@access PSM_t @*/
-
-static char * SCRIPT_PATH = "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin";
-
-/**
- * Return scriptlet name from tag.
- * @param tag scriptlet tag
- * @return name of scriptlet
- */
-static /*@observer@*/ const char * const tag2sln(int tag)
-{
- switch (tag) {
- case RPMTAG_PREIN: return "%pre";
- case RPMTAG_POSTIN: return "%post";
- case RPMTAG_PREUN: return "%preun";
- case RPMTAG_POSTUN: return "%postun";
- case RPMTAG_VERIFYSCRIPT: return "%verify";
- }
- return "%unknownscript";
-}
-
-/**
- * Run scriptlet with args.
- *
- * Run a script with an interpreter. If the interpreter is not specified,
- * /bin/sh will be used. If the interpreter is /bin/sh, then the args from
- * the header will be ignored, passing instead arg1 and arg2.
- *
- * @param psm package state machine data
- * @param h header
- * @param sln name of scriptlet section
- * @param progArgc no. of args from header
- * @param progArgv args from header, progArgv[0] is the interpreter to use
- * @param script scriptlet from header
- * @param arg1 no. instances of package installed after scriptlet exec
- * (-1 is no arg)
- * @param arg2 ditto, but for the target package
- * @return 0 on success, 1 on error
- */
-static int runScript(PSM_t psm, Header h,
- const char * sln,
- int progArgc, const char ** progArgv,
- const char * script, int arg1, int arg2)
-{
- const rpmTransactionSet ts = psm->ts;
- TFI_t fi = psm->fi;
- HGE_t hge = fi->hge;
- HFD_t hfd = fi->hfd;
- const char ** argv = NULL;
- int argc = 0;
- const char ** prefixes = NULL;
- int numPrefixes;
- int_32 ipt;
- const char * oldPrefix;
- int maxPrefixLength;
- int len;
- char * prefixBuf = NULL;
- pid_t child;
- int status = 0;
- const char * fn = NULL;
- int i;
- int freePrefixes = 0;
- FD_t out;
- int rc = 0;
- const char *n, *v, *r;
-
- if (!progArgv && !script)
- return 0;
-
- if (!progArgv) {
- argv = alloca(5 * sizeof(char *));
- argv[0] = "/bin/sh";
- argc = 1;
- } else {
- argv = alloca((progArgc + 4) * sizeof(char *));
- memcpy(argv, progArgv, progArgc * sizeof(char *));
- argc = progArgc;
- }
-
- headerNVR(h, &n, &v, &r);
- if (hge(h, RPMTAG_INSTPREFIXES, &ipt, (void **) &prefixes, &numPrefixes)) {
- freePrefixes = 1;
- } else if (hge(h, RPMTAG_INSTALLPREFIX, NULL, (void **) &oldPrefix, NULL)) {
- prefixes = &oldPrefix;
- numPrefixes = 1;
- } else {
- numPrefixes = 0;
- }
-
- maxPrefixLength = 0;
- for (i = 0; i < numPrefixes; i++) {
- len = strlen(prefixes[i]);
- if (len > maxPrefixLength) maxPrefixLength = len;
- }
- prefixBuf = alloca(maxPrefixLength + 50);
-
- if (script) {
- FD_t fd;
- if (makeTempFile((!ts->chrootDone ? ts->rootDir : "/"), &fn, &fd)) {
- if (freePrefixes) free(prefixes);
- return 1;
- }
-
- if (rpmIsDebug() &&
- (!strcmp(argv[0], "/bin/sh") || !strcmp(argv[0], "/bin/bash")))
- (void)Fwrite("set -x\n", sizeof(char), 7, fd);
-
- (void)Fwrite(script, sizeof(script[0]), strlen(script), fd);
- Fclose(fd);
-
- { const char * sn = fn;
- if (!ts->chrootDone &&
- !(ts->rootDir[0] == '/' && ts->rootDir[1] == '\0'))
- {
- sn += strlen(ts->rootDir)-1;
- }
- argv[argc++] = sn;
- }
-
- if (arg1 >= 0) {
- char *av = alloca(20);
- sprintf(av, "%d", arg1);
- argv[argc++] = av;
- }
- if (arg2 >= 0) {
- char *av = alloca(20);
- sprintf(av, "%d", arg2);
- argv[argc++] = av;
- }
- }
-
- argv[argc] = NULL;
-
- if (ts->scriptFd != NULL) {
- if (rpmIsVerbose()) {
- out = fdDup(Fileno(ts->scriptFd));
- } else {
- out = Fopen("/dev/null", "w.fdio");
- if (Ferror(out)) {
- out = fdDup(Fileno(ts->scriptFd));
- }
- }
- } else {
- out = fdDup(STDOUT_FILENO);
- out = fdLink(out, "runScript persist");
- }
-
- if (!(child = fork())) {
- const char * rootDir;
- int pipes[2];
-
- pipes[0] = pipes[1] = 0;
- /* make stdin inaccessible */
- pipe(pipes);
- close(pipes[1]);
- dup2(pipes[0], STDIN_FILENO);
- close(pipes[0]);
-
- if (ts->scriptFd != NULL) {
- if (Fileno(ts->scriptFd) != STDERR_FILENO)
- dup2(Fileno(ts->scriptFd), STDERR_FILENO);
- if (Fileno(out) != STDOUT_FILENO)
- dup2(Fileno(out), STDOUT_FILENO);
- /* make sure we don't close stdin/stderr/stdout by mistake! */
- if (Fileno(out) > STDERR_FILENO && Fileno(out) != Fileno(ts->scriptFd)) {
- Fclose (out);
- }
- if (Fileno(ts->scriptFd) > STDERR_FILENO) {
- Fclose (ts->scriptFd);
- }
- }
-
- { const char *ipath = rpmExpand("PATH=%{_install_script_path}", NULL);
- const char *path = SCRIPT_PATH;
-
- if (ipath && ipath[5] != '%')
- path = ipath;
- doputenv(path);
- if (ipath) free((void *)ipath);
- }
-
- for (i = 0; i < numPrefixes; i++) {
- sprintf(prefixBuf, "RPM_INSTALL_PREFIX%d=%s", i, prefixes[i]);
- doputenv(prefixBuf);
-
- /* backwards compatibility */
- if (i == 0) {
- sprintf(prefixBuf, "RPM_INSTALL_PREFIX=%s", prefixes[i]);
- doputenv(prefixBuf);
- }
- }
-
- rootDir = ts->rootDir;
- switch(urlIsURL(rootDir)) {
- case URL_IS_PATH:
- rootDir += sizeof("file://") - 1;
- rootDir = strchr(rootDir, '/');
- /*@fallthrough@*/
- case URL_IS_UNKNOWN:
- if (!ts->chrootDone && !(rootDir[0] == '/' && rootDir[1] == '\0')) {
- /*@-unrecog@*/ chroot(rootDir); /*@=unrecog@*/
- }
- chdir("/");
- execv(argv[0], (char *const *)argv);
- break;
- default:
- break;
- }
-
- _exit(-1);
- /*@notreached@*/
- }
-
- if (waitpid(child, &status, 0) < 0) {
- rpmError(RPMERR_SCRIPT,
- _("execution of %s scriptlet from %s-%s-%s failed, waitpid returned %s\n"),
- sln, n, v, r, strerror (errno));
- /* XXX what to do here? */
- rc = 0;
- } else {
- if (!WIFEXITED(status) || WEXITSTATUS(status)) {
- rpmError(RPMERR_SCRIPT,
- _("execution of %s scriptlet from %s-%s-%s failed, exit status %d\n"),
- sln, n, v, r, WEXITSTATUS(status));
- rc = 1;
- }
- }
-
- if (freePrefixes) prefixes = hfd(prefixes, ipt);
-
- Fclose(out); /* XXX dup'd STDOUT_FILENO */
-
- if (script) {
- if (!rpmIsDebug()) unlink(fn);
- free((void *)fn);
- }
-
- return rc;
-}
-
-int runInstScript(PSM_t psm)
-{
- const rpmTransactionSet ts = psm->ts;
- TFI_t fi = psm->fi;
- HGE_t hge = fi->hge;
- HFD_t hfd = fi->hfd;
- void ** programArgv;
- int programArgc;
- const char ** argv;
- int_32 ptt, stt;
- const char * script;
- int rc;
-
- if (ts->transFlags & RPMTRANS_FLAG_NOSCRIPTS)
- return 0;
-
- /*
- * headerGetEntry() sets the data pointer to NULL if the entry does
- * not exist.
- */
- hge(fi->h, psm->progTag, &ptt, (void **) &programArgv, &programArgc);
- hge(fi->h, psm->scriptTag, &stt, (void **) &script, NULL);
-
- if (programArgv && ptt == RPM_STRING_TYPE) {
- argv = alloca(sizeof(char *));
- *argv = (const char *) programArgv;
- } else {
- argv = (const char **) programArgv;
- }
-
- rc = runScript(psm, fi->h, tag2sln(psm->scriptTag), programArgc, argv,
- script, psm->scriptArg, -1);
- programArgv = hfd(programArgv, ptt);
- script = hfd(script, stt);
- return rc;
-}
-
-/**
- * @param psm package state machine data
- * @param sourceH
- * @param triggeredH
- * @param arg2
- * @param triggersAlreadyRun
- * @return
- */
-static int handleOneTrigger(PSM_t psm, Header sourceH, Header triggeredH,
- int arg2, char * triggersAlreadyRun)
-{
- const rpmTransactionSet ts = psm->ts;
- TFI_t fi = psm->fi;
- HGE_t hge = fi->hge;
- HFD_t hfd = fi->hfd;
- const char ** triggerNames;
- const char ** triggerEVR;
- const char ** triggerScripts;
- const char ** triggerProgs;
- int_32 * triggerFlags;
- int_32 * triggerIndices;
- int_32 tnt, tvt, tft;
- const char * triggerPackageName;
- const char * sourceName;
- int numTriggers;
- int rc = 0;
- int i;
- int skip;
-
- if (!hge(triggeredH, RPMTAG_TRIGGERNAME, &tnt,
- (void **) &triggerNames, &numTriggers))
- return 0;
-
- headerNVR(sourceH, &sourceName, NULL, NULL);
-
- hge(triggeredH, RPMTAG_TRIGGERFLAGS, &tft, (void **) &triggerFlags, NULL);
- hge(triggeredH, RPMTAG_TRIGGERVERSION, &tvt, (void **) &triggerEVR, NULL);
-
- for (i = 0; i < numTriggers; i++) {
- int_32 tit, tst, tpt;
-
- if (!(triggerFlags[i] & psm->sense)) continue;
- if (strcmp(triggerNames[i], sourceName)) continue;
-
- /*
- * For some reason, the TRIGGERVERSION stuff includes the name of
- * the package which the trigger is based on. We need to skip
- * over that here. I suspect that we'll change our minds on this
- * and remove that, so I'm going to just 'do the right thing'.
- */
- skip = strlen(triggerNames[i]);
- if (!strncmp(triggerEVR[i], triggerNames[i], skip) &&
- (triggerEVR[i][skip] == '-'))
- skip++;
- else
- skip = 0;
-
- if (!headerMatchesDepFlags(sourceH, triggerNames[i],
- triggerEVR[i] + skip, triggerFlags[i]))
- continue;
-
- hge(triggeredH, RPMTAG_TRIGGERINDEX, &tit,
- (void **) &triggerIndices, NULL);
- hge(triggeredH, RPMTAG_TRIGGERSCRIPTS, &tst,
- (void **) &triggerScripts, NULL);
- hge(triggeredH, RPMTAG_TRIGGERSCRIPTPROG, &tpt,
- (void **) &triggerProgs, NULL);
-
- headerNVR(triggeredH, &triggerPackageName, NULL, NULL);
-
- { int arg1;
- int index;
-
- arg1 = rpmdbCountPackages(ts->rpmdb, triggerPackageName);
- if (arg1 < 0) {
- rc = 1; /* XXX W2DO? same as "execution of script failed" */
- } else {
- arg1 += psm->countCorrection;
- index = triggerIndices[i];
- if (!triggersAlreadyRun || !triggersAlreadyRun[index]) {
- rc = runScript(psm, triggeredH, "%trigger", 1,
- triggerProgs + index, triggerScripts[index],
- arg1, arg2);
- if (triggersAlreadyRun) triggersAlreadyRun[index] = 1;
- }
- }
- }
-
- triggerIndices = hfd(triggerIndices, tit);
- triggerScripts = hfd(triggerScripts, tst);
- triggerProgs = hfd(triggerProgs, tpt);
-
- /*
- * Each target/source header pair can only result in a single
- * script being run.
- */
- break;
- }
-
- triggerNames = hfd(triggerNames, tnt);
- triggerFlags = hfd(triggerFlags, tft);
- triggerEVR = hfd(triggerEVR, tvt);
-
- return rc;
-}
-
-int runTriggers(PSM_t psm)
-{
- const rpmTransactionSet ts = psm->ts;
- TFI_t fi = psm->fi;
- int numPackage;
- int rc = 0;
-
- numPackage = rpmdbCountPackages(ts->rpmdb, fi->name) + psm->countCorrection;
- if (numPackage < 0)
- return 1;
-
- { Header triggeredH;
- rpmdbMatchIterator mi;
- int countCorrection = psm->countCorrection;
-
- psm->countCorrection = 0;
- mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_TRIGGERNAME, fi->name, 0);
- while((triggeredH = rpmdbNextIterator(mi)) != NULL) {
- rc |= handleOneTrigger(psm, fi->h, triggeredH, numPackage, NULL);
- }
-
- rpmdbFreeIterator(mi);
- psm->countCorrection = countCorrection;
- }
-
- return rc;
-}
-
-int runImmedTriggers(PSM_t psm)
-{
- const rpmTransactionSet ts = psm->ts;
- TFI_t fi = psm->fi;
- HGE_t hge = fi->hge;
- HFD_t hfd = fi->hfd;
- const char ** triggerNames;
- int numTriggers;
- int_32 * triggerIndices;
- int_32 tnt, tit;
- int numTriggerIndices;
- char * triggersRun;
- int rc = 0;
-
- if (!hge(fi->h, RPMTAG_TRIGGERNAME, &tnt,
- (void **) &triggerNames, &numTriggers))
- return 0;
-
- hge(fi->h, RPMTAG_TRIGGERINDEX, &tit, (void **) &triggerIndices,
- &numTriggerIndices);
- triggersRun = alloca(sizeof(*triggersRun) * numTriggerIndices);
- memset(triggersRun, 0, sizeof(*triggersRun) * numTriggerIndices);
-
- { Header sourceH = NULL;
- int i;
-
- for (i = 0; i < numTriggers; i++) {
- rpmdbMatchIterator mi;
-
- if (triggersRun[triggerIndices[i]]) continue;
-
- mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_NAME, triggerNames[i], 0);
-
- while((sourceH = rpmdbNextIterator(mi)) != NULL) {
- rc |= handleOneTrigger(psm, sourceH, fi->h,
- rpmdbGetIteratorCount(mi),
- triggersRun);
- }
-
- rpmdbFreeIterator(mi);
- }
- }
- triggerIndices = hfd(triggerNames, tit);
- triggerNames = hfd(triggerNames, tnt);
- return rc;
-}
diff --git a/lib/scriptlet.h b/lib/scriptlet.h
deleted file mode 100644
index 7ca356434..000000000
--- a/lib/scriptlet.h
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef H_SCRIPTLET
-#define H_SCRIPTLET
-
-/** \file lib/scriptlet.h
- */
-
-#include <rpmlib.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * Retrieve and run scriptlet from header.
- * @param psm package state machine data
- * @return 0 on success
- */
-int runInstScript(PSM_t psm)
- /*@modifies psm @*/;
-
-/**
- * Run trigger scripts in the database that are fired by this header.
- * @param psm package state machine data
- * @return 0 on success, 1 on error
- */
-int runTriggers(PSM_t psm)
- /*@modifies psm @*/;
-
-/**
- * Run triggers from this header that are fired by headers in the database.
- * @param psm package state machine data
- * @return 0 on success, 1 on error
- */
-int runImmedTriggers(PSM_t psm)
- /*@modifies psm @*/;
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* H_SCRIPTLET */
diff --git a/lib/verify.c b/lib/verify.c
index 008a222df..8810f9170 100644
--- a/lib/verify.c
+++ b/lib/verify.c
@@ -299,7 +299,7 @@ int rpmVerifyScript(const char * rootDir, Header h, FD_t scriptFd)
psm->fi = fi;
psm->scriptTag = RPMTAG_VERIFYSCRIPT;
psm->progTag = RPMTAG_VERIFYSCRIPTPROG;
- rc = runInstScript(psm);
+ rc = psmStage(psm, PSM_SCRIPT);
freeFi(fi);
fi = _free(fi);
rpmtransFree(ts);