diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Makefile.am | 4 | ||||
-rw-r--r-- | lib/psm.c | 605 | ||||
-rw-r--r-- | lib/psm.h | 48 | ||||
-rw-r--r-- | lib/scriptlet.c | 474 | ||||
-rw-r--r-- | lib/scriptlet.h | 41 | ||||
-rw-r--r-- | lib/verify.c | 2 |
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) @@ -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); @@ -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); |