./lib/fprint.c \
./lib/fprint.h \
./lib/fs.c \
+ ./lib/fsm.c \
+ ./lib/fsm.h \
./lib/hash.c \
./lib/hash.h \
./lib/header.c \
./lib/header.h \
- ./lib/install.c \
- ./lib/install.h \
./lib/md5.c \
./lib/md5.h \
./lib/md5sum.c \
./lib/poptBT.c \
./lib/poptQV.c \
./lib/problems.c \
+ ./lib/psm.c \
+ ./lib/psm.h \
./lib/query.c \
- ./lib/rollback.c \
./lib/rpmchecksig.c \
./lib/rpmdb.c \
./lib/rpmdb.h \
./lib/tagName.c \
./lib/tagtable.c \
./lib/transaction.c \
- ./lib/uninstall.c \
./lib/verify.c \
./rpmio/base64.c \
./rpmio/base64.h \
#include <rpmurl.h>
#include "build.h"
-#include "install.h"
#include "debug.h"
static int checkSpec(Header h)
* XXX this information will move elsewhere eventually
*/
-#include "rollback.h"
+#include "psm.h"
/**
*/
pkginc_HEADERS = \
header.h misc.h rpmlib.h stringbuf.h
noinst_HEADERS = \
- cpio.h depends.h falloc.h fprint.h hash.h install.h \
- md5.h rollback.h \
+ cpio.h depends.h falloc.h fprint.h fsm.h hash.h \
+ md5.h psm.h \
rpmdb.h rpmlead.h signature.h
mylibpaths = -L$(top_builddir)/lib/.libs -L$(top_builddir)/rpmio/.libs \
lib_LTLIBRARIES = librpm.la
librpm_la_SOURCES = \
cpio.c $(DBLIBSRCS) depends.c \
- formats.c fprint.c fs.c hash.c header.c install.c \
+ formats.c fprint.c fs.c fsm.c hash.c header.c \
md5.c md5sum.c misc.c package.c problems.c \
- poptBT.c poptQV.c query.c rollback.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 \
- tagName.c tagtable.c transaction.c uninstall.c verify.c
+ tagName.c tagtable.c transaction.c verify.c
librpm_la_LDFLAGS = @libdb3@ @libdb2@ @libdb1@
librpm_la_LIBADD = $(DBLIBOBJS)
librpm_la_DEPENDENCIES = $(DBLIBOBJS)
-/** \ingroup payload rpmio
+/** \ingroup payload
* \file lib/cpio.c
* Handle cpio payloads within rpm packages.
*
#include "system.h"
#include <rpmlib.h>
-#include "rollback.h"
+#include "fsm.h"
#include "rpmerr.h"
#include "debug.h"
-/*@access FD_t @*/
-/*@access rpmTransactionSet @*/
-/*@access TFI_t @*/
/*@access FSM_t @*/
-#define alloca_strdup(_s) strcpy(alloca(strlen(_s)+1), (_s))
+extern int _fsm_debug;
+/**
+ * Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
+ * @param this memory to free
+ * @retval NULL always
+ */
static /*@null@*/ void * _free(/*@only@*/ /*@null@*/ const void * this) {
if (this) free((void *)this);
return NULL;
}
-int _fsm_debug = 0;
-
-/** \ingroup payload
- * Keeps track of the set of all hard links to a file in an archive.
- */
-struct hardLink {
-/*@owned@*/ struct hardLink * next;
-/*@owned@*/ const char ** nsuffix;
-/*@owned@*/ int * filex;
- dev_t dev;
- ino_t inode;
- int nlink;
- int linksLeft;
- int linkIndex;
- int createdPath;
-};
-
-/**
- */
-typedef struct fsmIterator_s {
-/*@kept@*/ rpmTransactionSet ts; /*!< transaction set. */
-/*@kept@*/ TFI_t fi; /*!< transaction element file info. */
- int isave; /*!< last returned iterator index. */
- int i; /*!< iterator index. */
-} * FSMI_t;
-
-/** \ingroup payload
- * File name and stat information.
- */
-struct fsm_s {
-/*@owned@*/ const char * path; /*!< Current file name. */
-/*@owned@*/ const char * opath; /*!< Original file name. */
- FD_t cfd; /*!< Payload file handle. */
- FD_t rfd; /*!< read: File handle. */
-/*@dependent@*/ char * rdbuf; /*!< read: Buffer. */
-/*@owned@*/ char * rdb; /*!< read: Buffer allocated. */
- size_t rdsize; /*!< read: Buffer allocated size. */
- size_t rdlen; /*!< read: Number of bytes requested. */
- size_t rdnb; /*!< read: Number of bytes returned. */
- FD_t wfd; /*!< write: File handle. */
-/*@dependent@*/ char * wrbuf; /*!< write: Buffer. */
-/*@owned@*/ char * wrb; /*!< write: Buffer allocated. */
- size_t wrsize; /*!< write: Buffer allocated size. */
- size_t wrlen; /*!< write: Number of bytes requested. */
- size_t wrnb; /*!< write: Number of bytes returned. */
-/*@only@*/ FSMI_t iter; /*!< File iterator. */
- int ix; /*!< Current file iterator index. */
-/*@only@*/ struct hardLink * links; /*!< Pending hard linked file(s). */
-/*@only@*/ struct hardLink * li; /*!< Current hard linked file(s). */
-/*@kept@*/ unsigned int * archiveSize; /*!< Pointer to archive size. */
-/*@kept@*/ const char ** failedFile; /*!< First file name that failed. */
-/*@shared@*/ const char * subdir; /*!< Current file sub-directory. */
- char subbuf[64]; /* XXX eliminate */
-/*@observer@*/ const char * osuffix; /*!< Old, preserved, file suffix. */
-/*@observer@*/ const char * nsuffix; /*!< New, created, file suffix. */
-/*@shared@*/ const char * suffix; /*!< Current file suffix. */
- char sufbuf[64]; /* XXX eliminate */
-/*@only@*/ short * dnlx; /*!< Last dirpath verified indexes. */
-/*@only@*/ char * ldn; /*!< Last dirpath verified. */
- int ldnlen; /*!< Last dirpath current length. */
- int ldnalloc; /*!< Last dirpath allocated length. */
- int postpone; /*!< Skip remaining stages? */
- int diskchecked; /*!< Has stat(2) been performed? */
- int exists; /*!< Does current file exist on disk? */
- int mkdirsdone; /*!< Have "orphan" dirs been created? */
- int astriplen; /*!< Length of buildroot prefix. */
- int rc; /*!< External file stage return code. */
- int commit; /*!< Commit synchronously? */
- cpioMapFlags mapFlags; /*!< Bit(s) to control mapping. */
-/*@shared@*/ const char * archivePath; /*!< Path to store in cpio archive. */
-/*@shared@*/ const char * dirName; /*!< File directory name. */
-/*@shared@*/ const char * baseName; /*!< File base name. */
-/*@shared@*/ const char * fmd5sum; /*!< File MD5 sum (NULL disables). */
- unsigned fflags; /*!< File flags. */
- fileAction action; /*!< File disposition. */
- fileStage goal; /*!< Package state machine goal. */
- fileStage stage; /*!< External file stage. */
- struct stat sb; /*!< Current file stat(2) info. */
- struct stat osb; /*!< Original file stat(2) info. */
-};
-
-rpmTransactionSet fsmGetTs(const FSM_t fsm) {
- const FSMI_t iter = fsm->iter;
- return (iter ? iter->ts : NULL);
-}
-
-TFI_t fsmGetFi(const FSM_t fsm) {
- const FSMI_t iter = fsm->iter;
- return (iter ? iter->fi : NULL);
-}
-
-#define SUFFIX_RPMORIG ".rpmorig"
-#define SUFFIX_RPMSAVE ".rpmsave"
-#define SUFFIX_RPMNEW ".rpmnew"
-
-/**
- */
-static /*@only@*//*@null@*/ const char * fsmFsPath(/*@null@*/ const FSM_t fsm,
- /*@null@*/ const struct stat * st,
- /*@null@*/ const char * subdir,
- /*@null@*/ const char * suffix)
-{
- const char * s = NULL;
-
- if (fsm) {
- int nb;
- char * t;
- nb = strlen(fsm->dirName) +
- (st && subdir && !S_ISDIR(st->st_mode) ? strlen(subdir) : 0) +
- (st && suffix && !S_ISDIR(st->st_mode) ? strlen(suffix) : 0) +
- strlen(fsm->baseName) + 1;
- s = t = xmalloc(nb);
- t = stpcpy(t, fsm->dirName);
- if (st && subdir && !S_ISDIR(st->st_mode))
- t = stpcpy(t, subdir);
- t = stpcpy(t, fsm->baseName);
- if (st && suffix && !S_ISDIR(st->st_mode))
- t = stpcpy(t, suffix);
- }
- return s;
-}
-
-/**
- */
-static /*@null@*/ void * mapFreeIterator(/*@only@*//*@null@*/const void * this) {
- return _free((void *)this);
-}
-
-/**
- */
-static void *
-mapInitIterator(/*@kept@*/ const void * this, /*@kept@*/ const void * that)
-{
- rpmTransactionSet ts = (void *)this;
- TFI_t fi = (void *)that;
- FSMI_t iter = NULL;
-
- iter = xcalloc(1, sizeof(*iter));
- iter->ts = ts;
- iter->fi = fi;
- switch (fi->type) {
- case TR_ADDED: iter->i = 0; break;
- case TR_REMOVED: iter->i = fi->fc - 1; break;
- }
- iter->isave = iter->i;
- return iter;
-}
-
-/**
- */
-static int mapNextIterator(void * this) {
- FSMI_t iter = this;
- const TFI_t fi = iter->fi;
- int i = -1;
-
- switch (fi->type) {
- case TR_ADDED: if (iter->i < fi->fc) i = iter->i++; break;
- case TR_REMOVED: if (iter->i >= 0) i = iter->i--; break;
- }
- iter->isave = i;
- return i;
-}
-
-/**
- */
-typedef struct dnli_s {
-/*@dependent@*/ TFI_t fi;
-/*@only@*/ /*@null@*/ char * active;
- int reverse;
- int isave;
- int i;
-} * DNLI_t;
-
-/**
- */
-static /*@null@*/ void * dnlFreeIterator(/*@only@*//*@null@*/ const void * this)
-{
- if (this) {
- DNLI_t dnli = (void *)this;
- if (dnli->active) free(dnli->active);
- }
- return _free(this);
-}
-
-/**
- */
-static inline int dnlCount(const DNLI_t dnli) {
- return (dnli ? dnli->fi->dc : 0);
-}
-
-/**
- */
-static inline int dnlIndex(const DNLI_t dnli) {
- return (dnli ? dnli->isave : -1);
-}
-
-/**
- */
-static /*@only@*/ void * dnlInitIterator(const FSM_t fsm, int reverse)
-{
- TFI_t fi = fsmGetFi(fsm);
- DNLI_t dnli;
- int i, j;
-
- if (fi == NULL)
- return NULL;
- dnli = xcalloc(1, sizeof(*dnli));
- dnli->fi = fi;
- dnli->reverse = reverse;
- dnli->i = (reverse ? fi->dc : 0);
-
- if (fi->dc) {
- dnli->active = xcalloc(fi->dc, sizeof(*dnli->active));
-
- /* Identify parent directories not skipped. */
- for (i = 0; i < fi->fc; i++)
- if (!XFA_SKIPPING(fi->actions[i])) dnli->active[fi->dil[i]] = 1;
-
- /* Exclude parent directories that are explicitly included. */
- for (i = 0; i < fi->fc; i++) {
- int dil, dnlen, bnlen;
-
- if (!S_ISDIR(fi->fmodes[i]))
- continue;
-
- dil = fi->dil[i];
- dnlen = strlen(fi->dnl[dil]);
- bnlen = strlen(fi->bnl[i]);
-
- for (j = 0; j < fi->dc; j++) {
- const char * dnl;
- int jlen;
-
- if (!dnli->active[j] || j == dil) continue;
- dnl = fi->dnl[j];
- jlen = strlen(dnl);
- if (jlen != (dnlen+bnlen+1)) continue;
- if (strncmp(dnl, fi->dnl[dil], dnlen)) continue;
- if (strncmp(dnl+dnlen, fi->bnl[i], bnlen)) continue;
- if (dnl[dnlen+bnlen] != '/' || dnl[dnlen+bnlen+1] != '\0')
- continue;
- /* This directory is included in the package. */
- dnli->active[j] = 0;
- break;
- }
- }
-
- /* Print only once per package. */
- if (!reverse) {
- j = 0;
- for (i = 0; i < fi->dc; i++) {
- if (!dnli->active[i]) continue;
- if (j == 0) {
- j = 1;
- rpmMessage(RPMMESS_DEBUG,
- _("========= Directories not explictly included in package:\n"));
- }
- rpmMessage(RPMMESS_DEBUG, _("%9d %s\n"), i, fi->dnl[i]);
- }
- if (j)
- rpmMessage(RPMMESS_DEBUG, "=========\n");
- }
- }
- return dnli;
-}
-
-/**
- */
-static const char * dnlNextIterator(/*@null@*/ DNLI_t dnli) {
- const char * dn = NULL;
-
- if (dnli && dnli->active) {
- TFI_t fi = dnli->fi;
- int i = -1;
-
- do {
- i = (!dnli->reverse ? dnli->i++ : --dnli->i);
- } while (i >= 0 && i < fi->dc && !dnli->active[i]);
-
- if (i >= 0 && i < fi->dc)
- dn = fi->dnl[i];
- else
- i = -1;
- dnli->isave = i;
- }
- return dn;
-}
-
-/**
- */
-static int cpioStrCmp(const void * a, const void * b) {
- const char * afn = *(const char **)a;
- const char * bfn = *(const char **)b;
-
- /* Match rpm-4.0 payloads with ./ prefixes. */
- if (afn[0] == '.' && afn[1] == '/') afn += 2;
- if (bfn[0] == '.' && bfn[1] == '/') bfn += 2;
-
- /* If either path is absolute, make it relative. */
- if (afn[0] == '/') afn += 1;
- if (bfn[0] == '/') bfn += 1;
-
- return strcmp(afn, bfn);
-}
-
-/**
- */
-static int mapFind(void * this, const char * fsmPath) {
- FSMI_t iter = this;
- const TFI_t fi = iter->fi;
- int ix = -1;
-
- if (fi) {
- const char ** p;
-
- p = bsearch(&fsmPath, fi->apath, fi->fc, sizeof(fsmPath), cpioStrCmp);
- if (p == NULL) {
- fprintf(stderr, "*** not mapped %s\n", fsmPath);
- } else {
- iter->i = p - fi->apath;
- ix = mapNextIterator(iter);
- }
- }
- return ix;
-}
-
-/**
- * Save hard link in chain.
- * @return Is chain only partially filled?
- */
-static int saveHardLink(FSM_t fsm)
-{
- struct stat * st = &fsm->sb;
- int rc = 0;
- int ix = -1;
- int j;
-
- /* Find hard link set. */
- for (fsm->li = fsm->links; fsm->li; fsm->li = fsm->li->next) {
- if (fsm->li->inode == st->st_ino && fsm->li->dev == st->st_dev)
- break;
- }
-
- /* New hard link encountered, add new link to set. */
- if (fsm->li == NULL) {
- fsm->li = xcalloc(1, sizeof(*fsm->li));
- fsm->li->next = NULL;
- fsm->li->nlink = st->st_nlink;
- fsm->li->dev = st->st_dev;
- fsm->li->inode = st->st_ino;
- fsm->li->linkIndex = -1;
- fsm->li->createdPath = -1;
-
- fsm->li->filex = xcalloc(st->st_nlink, sizeof(fsm->li->filex[0]));
- memset(fsm->li->filex, -1, (st->st_nlink * sizeof(fsm->li->filex[0])));
- fsm->li->nsuffix = xcalloc(st->st_nlink, sizeof(*fsm->li->nsuffix));
-
- if (fsm->goal == FSM_PKGBUILD)
- fsm->li->linksLeft = st->st_nlink;
- if (fsm->goal == FSM_PKGINSTALL)
- fsm->li->linksLeft = 0;
-
- fsm->li->next = fsm->links;
- fsm->links = fsm->li;
- }
-
- if (fsm->goal == FSM_PKGBUILD) --fsm->li->linksLeft;
- fsm->li->filex[fsm->li->linksLeft] = fsm->ix;
- /*@-observertrans@*/
- fsm->li->nsuffix[fsm->li->linksLeft] = fsm->nsuffix;
- /*@=observertrans@*/
- if (fsm->goal == FSM_PKGINSTALL) fsm->li->linksLeft++;
-
-#if 0
-fprintf(stderr, "*** %p link[%d:%d] %d filex %d %s\n", fsm->li, fsm->li->linksLeft, st->st_nlink, (int)st->st_size, fsm->li->filex[fsm->li->linksLeft], fsm->li->files[fsm->li->linksLeft]);
-#endif
-
- if (fsm->goal == FSM_PKGBUILD)
- return (fsm->li->linksLeft > 0);
-
- if (fsm->goal != FSM_PKGINSTALL)
- return 0;
-
- if (!(st->st_size || fsm->li->linksLeft == st->st_nlink))
- return 1;
-
- /* Here come the bits, time to choose a non-skipped file name. */
- { TFI_t fi = fsmGetFi(fsm);
-
- for (j = fsm->li->linksLeft - 1; j >= 0; j--) {
- ix = fsm->li->filex[j];
- if (ix < 0 || XFA_SKIPPING(fi->actions[ix]))
- continue;
- break;
- }
- }
-
- /* Are all links skipped or not encountered yet? */
- if (ix < 0 || j < 0)
- return 1; /* XXX W2DO? */
-
- /* Save the non-skipped file name and map index. */
- fsm->li->linkIndex = j;
- fsm->path = _free(fsm->path);
- fsm->ix = ix;
- rc = fsmStage(fsm, FSM_MAP);
- return rc;
-}
-
-/**
- * Destroy set of hard links.
- * @param li set of hard links
- */
-static /*@null@*/ void * freeHardLink(/*@only@*/ /*@null@*/ struct hardLink * li)
-{
- if (li) {
- li->nsuffix = _free(li->nsuffix); /* XXX elements are shared */
- li->filex = _free(li->filex);
- }
- return _free(li);
-}
-
-FSM_t newFSM(void) {
- FSM_t fsm = xcalloc(1, sizeof(*fsm));
- return fsm;
-}
-
-FSM_t freeFSM(FSM_t fsm)
-{
- if (fsm) {
- if (fsm->path) free((void *)fsm->path);
- while ((fsm->li = fsm->links) != NULL) {
- fsm->links = fsm->li->next;
- fsm->li->next = NULL;
- fsm->li = freeHardLink(fsm->li);
- }
- fsm->dnlx = _free(fsm->dnlx);
- fsm->ldn = _free(fsm->ldn);
- fsm->iter = mapFreeIterator(fsm->iter);
- }
- return _free(fsm);
-}
-
/**
* Convert string to unsigned integer (with buffer size check).
* @param input string
if (!rc && fsm->rdnb != fsm->wrlen)
rc = CPIOERR_BAD_HEADER;
if (rc) {
- free(t);
+ t = _free(t);
fsm->path = NULL;
return rc;
}
return 0;
}
-int fsmSetup(FSM_t fsm, fileStage goal,
- const rpmTransactionSet ts, const TFI_t fi, FD_t cfd,
- unsigned int * archiveSize, const char ** failedFile)
-{
- size_t pos = 0;
- int rc;
-
- fsm->goal = goal;
- if (cfd) {
- fsm->cfd = fdLink(cfd, "persist (fsm)");
- pos = fdGetCpioPos(fsm->cfd);
- fdSetCpioPos(fsm->cfd, 0);
- }
- fsm->iter = mapInitIterator(ts, fi);
-
- if (fsm->goal == FSM_PKGINSTALL) {
- if (ts && ts->notify) {
- (void)ts->notify(fi->h, RPMCALLBACK_INST_START, 0, fi->archiveSize,
- (fi->ap ? fi->ap->key : NULL), ts->notifyData);
- }
- }
-
- fsm->archiveSize = archiveSize;
- if (fsm->archiveSize)
- *fsm->archiveSize = 0;
- fsm->failedFile = failedFile;
- if (fsm->failedFile)
- *fsm->failedFile = NULL;
-
- memset(fsm->sufbuf, 0, sizeof(fsm->sufbuf));
- if (fsm->goal == FSM_PKGINSTALL) {
- if (ts->id > 0)
- sprintf(fsm->sufbuf, ";%08x", (unsigned)ts->id);
- }
-
- rc = fsm->rc = 0;
- rc = fsmStage(fsm, FSM_CREATE);
-
- rc = fsmStage(fsm, fsm->goal);
-
- if (!rc && fsm->archiveSize)
- *fsm->archiveSize = (fdGetCpioPos(fsm->cfd) - pos);
-
- return rc;
-}
-
-int fsmTeardown(FSM_t fsm) {
- int rc = fsm->rc;
-
- if (!rc)
- rc = fsmStage(fsm, FSM_DESTROY);
-
- fsm->iter = mapFreeIterator(fsm->iter);
- if (fsm->cfd) {
- fsm->cfd = fdFree(fsm->cfd, "persist (fsm)");
- fsm->cfd = NULL;
- }
- fsm->failedFile = NULL;
- return rc;
-}
-
-int fsmMapPath(FSM_t fsm)
-{
- TFI_t fi = fsmGetFi(fsm); /* XXX const except for fstates */
- int rc = 0;
- int i;
-
- fsm->osuffix = NULL;
- fsm->nsuffix = NULL;
- fsm->astriplen = 0;
- fsm->action = FA_UNKNOWN;
- fsm->mapFlags = 0;
-
- i = fsm->ix;
- if (fi && i >= 0 && i < fi->fc) {
-
- fsm->astriplen = fi->astriplen;
- fsm->action = (fi->actions ? fi->actions[i] : fi->action);
- fsm->fflags = (fi->fflags ? fi->fflags[i] : fi->flags);
- fsm->mapFlags = (fi->fmapflags ? fi->fmapflags[i] : fi->mapflags);
-
- /* src rpms have simple base name in payload. */
- fsm->archivePath =
- (fi->apath ? fi->apath[i] + fi->striplen : fi->bnl[i]);
- fsm->dirName = fi->dnl[fi->dil[i]];
- fsm->baseName = fi->bnl[i];
-
- switch (fsm->action) {
- case FA_SKIP:
- break;
- case FA_SKIPMULTILIB: /* XXX RPMFILE_STATE_MULTILIB? */
-fprintf(stderr, "*** %s:%s %s\n", fiTypeString(fi), fileActionString(fsm->action), (fsm->path ? fsm->path : ""));
- break;
- case FA_UNKNOWN:
-fprintf(stderr, "*** %s:%s %s\n", fiTypeString(fi), fileActionString(fsm->action), (fsm->path ? fsm->path : ""));
- break;
-
- case FA_CREATE:
- assert(fi->type == TR_ADDED);
- break;
-
- case FA_SKIPNSTATE:
-fprintf(stderr, "*** %s:%s %s\n", fiTypeString(fi), fileActionString(fsm->action), (fsm->path ? fsm->path : ""));
- if (fi->type == TR_ADDED)
- fi->fstates[i] = RPMFILE_STATE_NOTINSTALLED;
- break;
-
- case FA_SKIPNETSHARED:
- if (fi->type == TR_ADDED)
- fi->fstates[i] = RPMFILE_STATE_NETSHARED;
- break;
-
- case FA_BACKUP:
-fprintf(stderr, "*** %s:%s %s\n", fiTypeString(fi), fileActionString(fsm->action), (fsm->path ? fsm->path : ""));
- switch (fi->type) {
- case TR_ADDED:
- fsm->osuffix = SUFFIX_RPMORIG;
- break;
- case TR_REMOVED:
- fsm->osuffix = SUFFIX_RPMSAVE;
- break;
- }
- break;
-
- case FA_ALTNAME:
- assert(fi->type == TR_ADDED);
- fsm->nsuffix = SUFFIX_RPMNEW;
- break;
-
- case FA_SAVE:
-fprintf(stderr, "*** %s:%s %s\n", fiTypeString(fi), fileActionString(fsm->action), (fsm->path ? fsm->path : ""));
- assert(fi->type == TR_ADDED);
- fsm->osuffix = SUFFIX_RPMSAVE;
- break;
- case FA_ERASE:
- assert(fi->type == TR_REMOVED);
- break;
- default:
-fprintf(stderr, "*** %s:%s %s\n", fiTypeString(fi), fileActionString(fsm->action), (fsm->path ? fsm->path : ""));
- break;
- }
-
- if ((fsm->mapFlags & CPIO_MAP_PATH) || fsm->nsuffix) {
- const struct stat * st = &fsm->sb;
- fsm->path = _free(fsm->path);
- fsm->path = fsmFsPath(fsm, st, fsm->subdir,
- (fsm->suffix ? fsm->suffix : fsm->nsuffix));
- }
- }
- return rc;
-}
-
-int fsmMapAttrs(FSM_t fsm)
-{
- struct stat * st = &fsm->sb;
- TFI_t fi = fsmGetFi(fsm);
- int i = fsm->ix;
-
- if (fi && i >= 0 && i < fi->fc) {
- mode_t perms =
- (S_ISDIR(st->st_mode) ? fi->dperms : fi->fperms);
- mode_t finalMode =
- (fi->fmodes ? fi->fmodes[i] : perms);
- uid_t finalUid =
- (fi->fuids ? fi->fuids[i] : fi->uid); /* XXX chmod u-s */
- gid_t finalGid =
- (fi->fgids ? fi->fgids[i] : fi->gid); /* XXX chmod g-s */
-
- if (fsm->mapFlags & CPIO_MAP_MODE)
- st->st_mode = (st->st_mode & S_IFMT) | finalMode;
- if (fsm->mapFlags & CPIO_MAP_UID)
- st->st_uid = finalUid;
- if (fsm->mapFlags & CPIO_MAP_GID)
- st->st_gid = finalGid;
-
- fsm->fmd5sum = (fi->fmd5s ? fi->fmd5s[i] : NULL);
-
- }
- return 0;
-}
-
-/**
- * Create file from payload stream.
- * @todo Legacy: support brokenEndian MD5 checks?
- * @param fsm file path and stat info
- * @return 0 on success
- */
-static int expandRegular(FSM_t fsm)
- /*@modifies fileSystem, fsm @*/
-{
- const char * fmd5sum;
- const struct stat * st = &fsm->sb;
- int left = st->st_size;
- int rc = 0;
-
- rc = fsmStage(fsm, FSM_WOPEN);
- if (rc)
- goto exit;
-
- /* XXX md5sum's will break on repackaging that includes modified files. */
- fmd5sum = fsm->fmd5sum;
-
- /* XXX This doesn't support brokenEndian checks. */
- if (st->st_size > 0 && fmd5sum)
- fdInitMD5(fsm->wfd, 0);
-
- while (left) {
-
- fsm->wrlen = (left > fsm->wrsize ? fsm->wrsize : left);
- rc = fsmStage(fsm, FSM_DREAD);
- if (rc)
- goto exit;
-
- rc = fsmStage(fsm, FSM_WRITE);
- if (rc)
- goto exit;
-
- left -= fsm->wrnb;
-
- /* don't call this with fileSize == fileComplete */
- if (!rc && left)
- (void) fsmStage(fsm, FSM_NOTIFY);
- }
-
- if (st->st_size > 0 && fmd5sum) {
- const char * md5sum = NULL;
-
- Fflush(fsm->wfd);
- fdFiniMD5(fsm->wfd, (void **)&md5sum, NULL, 1);
-
- if (md5sum == NULL) {
- rc = CPIOERR_MD5SUM_MISMATCH;
- } else {
- if (strcmp(md5sum, fmd5sum))
- rc = CPIOERR_MD5SUM_MISMATCH;
- md5sum = _free(md5sum);
- }
- }
-
-exit:
- (void) fsmStage(fsm, FSM_WCLOSE);
- return rc;
-}
-
-/**
- * Write next item to payload stream.
- * @retval sizep address of no. bytes written
- * @param writeData should data be written?
- * @return 0 on success
- */
-static int writeFile(FSM_t fsm, int writeData)
- /*@modifies fsm @*/
-{
- const char * path = fsm->path;
- const char * opath = fsm->opath;
- struct stat * st = &fsm->sb;
- struct stat * ost = &fsm->osb;
- size_t pos = fdGetCpioPos(fsm->cfd);
- int left;
- int rc;
-
- st->st_size = (writeData ? ost->st_size : 0);
- if (S_ISDIR(st->st_mode)) {
- st->st_size = 0;
- } else if (S_ISLNK(st->st_mode)) {
- /*
- * While linux puts the size of a symlink in the st_size field,
- * I don't think that's a specified standard.
- */
- /* XXX NUL terminated result in fsm->rdbuf, len in fsm->rdnb. */
- rc = fsmStage(fsm, FSM_READLINK);
- if (rc) goto exit;
- st->st_size = fsm->rdnb;
- }
-
- if (fsm->mapFlags & CPIO_MAP_PATH)
- fsm->path = fsm->archivePath;
- rc = fsmStage(fsm, FSM_HWRITE);
- fsm->path = path;
- if (rc) goto exit;
-
- if (writeData && S_ISREG(st->st_mode)) {
-#if HAVE_MMAP
- char * rdbuf = NULL;
- void * mapped = (void *)-1;
- size_t nmapped;
-#endif
-
- rc = fsmStage(fsm, FSM_ROPEN);
- if (rc) goto exit;
-
- /* XXX unbuffered mmap generates *lots* of fdio debugging */
-#if HAVE_MMAP
- nmapped = 0;
- mapped = mmap(NULL, st->st_size, PROT_READ, MAP_SHARED, Fileno(fsm->rfd), 0);
- if (mapped != (void *)-1) {
- rdbuf = fsm->rdbuf;
- fsm->rdbuf = (char *) mapped;
- fsm->rdlen = nmapped = st->st_size;
- }
-#endif
-
- left = st->st_size;
-
- while (left) {
-#if HAVE_MMAP
- if (mapped != (void *)-1) {
- fsm->rdnb = nmapped;
- } else
-#endif
- {
- fsm->rdlen = (left > fsm->rdsize ? fsm->rdsize : left),
- rc = fsmStage(fsm, FSM_READ);
- if (rc) goto exit;
- }
-
- /* XXX DWRITE uses rdnb for I/O length. */
- rc = fsmStage(fsm, FSM_DWRITE);
- if (rc) goto exit;
-
- left -= fsm->wrnb;
- }
-
-#if HAVE_MMAP
- if (mapped != (void *)-1) {
- /*@-noeffect@*/ munmap(mapped, nmapped) /*@=noeffect@*/;
- fsm->rdbuf = rdbuf;
- }
-#endif
-
- } else if (writeData && S_ISLNK(st->st_mode)) {
- /* XXX DWRITE uses rdnb for I/O length. */
- rc = fsmStage(fsm, FSM_DWRITE);
- if (rc) goto exit;
- }
-
- rc = fsmStage(fsm, FSM_PAD);
- if (rc) goto exit;
-
- { const rpmTransactionSet ts = fsmGetTs(fsm);
- TFI_t fi = fsmGetFi(fsm);
- if (ts && fi && ts->notify) {
- size_t size = (fdGetCpioPos(fsm->cfd) - pos);
- (void)ts->notify(fi->h, RPMCALLBACK_INST_PROGRESS, size, size,
- (fi->ap ? fi->ap->key : NULL), ts->notifyData);
- }
- }
-
- rc = 0;
-
-exit:
- if (fsm->rfd)
- (void) fsmStage(fsm, FSM_RCLOSE);
- fsm->opath = opath;
- fsm->path = path;
- return rc;
-}
-
-/**
- * Write set of linked files to payload stream.
- * @return 0 on success
- */
-static int writeLinkedFile(FSM_t fsm)
- /*@modifies fsm @*/
-{
- const char * path = fsm->path;
- const char * nsuffix = fsm->nsuffix;
- int iterIndex = fsm->ix;
- int ec = 0;
- int rc;
- int i;
-
- fsm->path = NULL;
- fsm->nsuffix = NULL;
- fsm->ix = -1;
-
- for (i = fsm->li->nlink - 1; i >= 0; i--) {
- if (fsm->li->filex[i] < 0) continue;
-
- fsm->ix = fsm->li->filex[i];
- rc = fsmStage(fsm, FSM_MAP);
-
- /* Write data after last link. */
- rc = writeFile(fsm, (i == 0));
- if (rc && fsm->failedFile && *fsm->failedFile == NULL) {
- ec = rc;
- *fsm->failedFile = xstrdup(fsm->path);
- }
-
- fsm->path = _free(fsm->path);
- fsm->li->filex[i] = -1;
- }
-
- fsm->ix = iterIndex;
- fsm->nsuffix = nsuffix;
- fsm->path = path;
- return ec;
-}
-
-/**
- */
-static int fsmMakeLinks(FSM_t fsm)
-{
- const char * path = fsm->path;
- const char * opath = fsm->opath;
- const char * nsuffix = fsm->nsuffix;
- int iterIndex = fsm->ix;
- int ec = 0;
- int rc;
- int i;
-
- fsm->path = NULL;
- fsm->opath = NULL;
- fsm->nsuffix = NULL;
- fsm->ix = -1;
-
- fsm->ix = fsm->li->filex[fsm->li->createdPath];
- rc = fsmStage(fsm, FSM_MAP);
- fsm->opath = fsm->path;
- fsm->path = NULL;
- for (i = 0; i < fsm->li->nlink; i++) {
- if (fsm->li->filex[i] < 0) continue;
- if (i == fsm->li->createdPath) continue;
-
- fsm->ix = fsm->li->filex[i];
- rc = fsmStage(fsm, FSM_MAP);
- rc = fsmStage(fsm, FSM_VERIFY);
- if (!rc) continue;
- if (rc != CPIOERR_LSTAT_FAILED) break;
-
- /* XXX link(fsm->opath, fsm->path) */
- rc = fsmStage(fsm, FSM_LINK);
- if (rc && fsm->failedFile && *fsm->failedFile == NULL) {
- ec = rc;
- *fsm->failedFile = xstrdup(fsm->path);
- }
-
- fsm->li->linksLeft--;
- }
- fsm->opath = _free(fsm->opath);
-
- fsm->ix = iterIndex;
- fsm->nsuffix = nsuffix;
- fsm->path = path;
- fsm->opath = opath;
- return ec;
-}
-
-/**
- */
-static int fsmCommitLinks(FSM_t fsm)
-{
- const char * path = fsm->path;
- const char * nsuffix = fsm->nsuffix;
- int iterIndex = fsm->ix;
- struct stat * st = &fsm->sb;
- int rc = 0;
- int i;
-
- fsm->path = NULL;
- fsm->nsuffix = NULL;
- fsm->ix = -1;
-
- for (fsm->li = fsm->links; fsm->li; fsm->li = fsm->li->next) {
- if (fsm->li->inode == st->st_ino && fsm->li->dev == st->st_dev)
- break;
- }
-
- for (i = 0; i < fsm->li->nlink; i++) {
- if (fsm->li->filex[i] < 0) continue;
- fsm->ix = fsm->li->filex[i];
- rc = fsmStage(fsm, FSM_MAP);
- rc = fsmStage(fsm, FSM_COMMIT);
- fsm->path = _free(fsm->path);
- fsm->li->filex[i] = -1;
- }
-
- fsm->ix = iterIndex;
- fsm->nsuffix = nsuffix;
- fsm->path = path;
- return rc;
-}
-
-int fsmStage(FSM_t fsm, fileStage stage)
-{
-#ifdef UNUSED
- fileStage prevStage = fsm->stage;
- const char * const prev = fileStageString(prevStage);
-#endif
- static int modulo = 4;
- const char * const cur = fileStageString(stage);
- struct stat * st = &fsm->sb;
- struct stat * ost = &fsm->osb;
- int saveerrno = errno;
- int rc = fsm->rc;
- int left;
- int i;
-
- if (stage & FSM_DEAD) {
- /* do nothing */
- } else if (stage & FSM_INTERNAL) {
- if (_fsm_debug && !(stage & FSM_SYSCALL))
- rpmMessage(RPMMESS_DEBUG, " %8s %06o%3d (%4d,%4d)%10d %s %s\n",
- cur,
- st->st_mode, st->st_nlink, st->st_uid, st->st_gid, st->st_size,
- (fsm->path ? fsm->path : ""),
- ((fsm->action != FA_UNKNOWN && fsm->action != FA_CREATE)
- ? fileActionString(fsm->action) : ""));
- } else {
- fsm->stage = stage;
- if (_fsm_debug || !(stage & FSM_VERBOSE))
- rpmMessage(RPMMESS_DEBUG, "%-8s %06o%3d (%4d,%4d)%10d %s %s\n",
- cur,
- st->st_mode, st->st_nlink, st->st_uid, st->st_gid, st->st_size,
- (fsm->path ? fsm->path + fsm->astriplen : ""),
- ((fsm->action != FA_UNKNOWN && fsm->action != FA_CREATE)
- ? fileActionString(fsm->action) : ""));
- }
-
- switch (stage) {
- case FSM_UNKNOWN:
- break;
- case FSM_PKGINSTALL:
- while (1) {
- /* Clean fsm, free'ing memory. Read next archive header. */
- rc = fsmStage(fsm, FSM_INIT);
-
- /* Exit on end-of-payload. */
- if (rc == CPIOERR_HDR_TRAILER) {
- rc = 0;
- break;
- }
-
- /* Exit on error. */
- if (rc) {
- fsm->postpone = 1;
- (void) fsmStage(fsm, FSM_UNDO);
- break;
- }
-
- /* Extract file from archive. */
- rc = fsmStage(fsm, FSM_PROCESS);
- if (rc) {
- (void) fsmStage(fsm, FSM_UNDO);
- break;
- }
-
- /* Notify on success. */
- (void) fsmStage(fsm, FSM_NOTIFY);
-
- if (fsmStage(fsm, FSM_FINI))
- break;
- }
- break;
- case FSM_PKGERASE:
- case FSM_PKGCOMMIT:
- while (1) {
- /* Clean fsm, free'ing memory. */
- rc = fsmStage(fsm, FSM_INIT);
-
- /* Exit on end-of-payload. */
- if (rc == CPIOERR_HDR_TRAILER) {
- rc = 0;
- break;
- }
-
- /* Rename/erase next item. */
- if (fsmStage(fsm, FSM_FINI))
- break;
- }
- break;
- case FSM_PKGBUILD:
- while (1) {
-
- rc = fsmStage(fsm, FSM_INIT);
-
- /* Exit on end-of-payload. */
- if (rc == CPIOERR_HDR_TRAILER) {
- rc = 0;
- break;
- }
-
- /* Exit on error. */
- if (rc) {
- fsm->postpone = 1;
- (void) fsmStage(fsm, FSM_UNDO);
- break;
- }
-
- /* Copy file into archive. */
- rc = fsmStage(fsm, FSM_PROCESS);
- if (rc) {
- (void) fsmStage(fsm, FSM_UNDO);
- break;
- }
-
- if (fsmStage(fsm, FSM_FINI))
- break;
- }
-
- if (!rc)
- rc = fsmStage(fsm, FSM_TRAILER);
- break;
- case FSM_CREATE:
- { rpmTransactionSet ts = fsmGetTs(fsm);
-#define _tsmask (RPMTRANS_FLAG_PKGCOMMIT | RPMTRANS_FLAG_COMMIT)
- fsm->commit = ((ts && (ts->transFlags & _tsmask) &&
- fsm->goal != FSM_PKGCOMMIT) ? 0 : 1);
-#undef _tsmask
- }
- fsm->path = _free(fsm->path);
- fsm->opath = _free(fsm->opath);
- fsm->dnlx = _free(fsm->dnlx);
-
- fsm->ldn = _free(fsm->ldn);
- fsm->ldnalloc = fsm->ldnlen = 0;
-
- fsm->rdsize = fsm->wrsize = 0;
- fsm->rdbuf = fsm->rdb = _free(fsm->rdb);
- fsm->wrbuf = fsm->wrb = _free(fsm->wrb);
- if (fsm->goal == FSM_PKGINSTALL || fsm->goal == FSM_PKGBUILD) {
- fsm->rdsize = 8 * BUFSIZ;
- fsm->rdbuf = fsm->rdb = xmalloc(fsm->rdsize);
- fsm->wrsize = 8 * BUFSIZ;
- fsm->wrbuf = fsm->wrb = xmalloc(fsm->wrsize);
- }
-
- fsm->mkdirsdone = 0;
- fsm->ix = -1;
- fsm->links = NULL;
- fsm->li = NULL;
- errno = 0; /* XXX get rid of EBADF */
-
- /* Detect and create directories not explicitly in package. */
- if (fsm->goal == FSM_PKGINSTALL) {
- rc = fsmStage(fsm, FSM_MKDIRS);
- if (!rc) fsm->mkdirsdone = 1;
- }
-
- break;
- case FSM_INIT:
- fsm->path = _free(fsm->path);
- fsm->postpone = 0;
- fsm->diskchecked = fsm->exists = 0;
- fsm->subdir = NULL;
- fsm->suffix = (fsm->sufbuf[0] != '\0' ? fsm->sufbuf : NULL);
- fsm->action = FA_UNKNOWN;
- fsm->osuffix = NULL;
- fsm->nsuffix = NULL;
-
- if (fsm->goal == FSM_PKGINSTALL) {
- /* Read next header from payload, checking for end-of-payload. */
- rc = fsmStage(fsm, FSM_NEXT);
- }
- if (rc) break;
-
- /* Identify mapping index. */
- fsm->ix = ((fsm->goal == FSM_PKGINSTALL)
- ? mapFind(fsm->iter, fsm->path) : mapNextIterator(fsm->iter));
-
- /* On non-install, detect end-of-loop. */
- if (fsm->goal != FSM_PKGINSTALL && fsm->ix < 0) {
- rc = CPIOERR_HDR_TRAILER;
- break;
- }
-
- /* On non-install, mode must be known so that dirs don't get suffix. */
- if (fsm->goal != FSM_PKGINSTALL) {
- TFI_t fi = fsmGetFi(fsm);
- st->st_mode = fi->fmodes[fsm->ix];
- }
-
- /* Generate file path. */
- rc = fsmStage(fsm, FSM_MAP);
- if (rc) break;
-
- /* Perform lstat/stat for disk file. */
- rc = fsmStage(fsm, (!(fsm->mapFlags & CPIO_FOLLOW_SYMLINKS)
- ? FSM_LSTAT : FSM_STAT));
- if (rc == CPIOERR_LSTAT_FAILED && errno == ENOENT) {
- errno = saveerrno;
- rc = 0;
- fsm->exists = 0;
- } else if (rc == 0) {
- fsm->exists = 1;
- }
- fsm->diskchecked = 1;
- if (rc) break;
-
- /* On non-install, the disk file stat is what's remapped. */
- if (fsm->goal != FSM_PKGINSTALL)
- *st = *ost; /* structure assignment */
-
- /* Remap file perms, owner, and group. */
- rc = fsmMapAttrs(fsm);
- if (rc) break;
-
- fsm->postpone = XFA_SKIPPING(fsm->action);
- if (fsm->goal == FSM_PKGINSTALL || fsm->goal == FSM_PKGBUILD) {
- if (!S_ISDIR(st->st_mode) && st->st_nlink > 1)
- fsm->postpone = saveHardLink(fsm);
- }
- break;
- case FSM_PRE:
- break;
- case FSM_MAP:
- rc = fsmMapPath(fsm);
- break;
- case FSM_MKDIRS:
- { const char * path = fsm->path;
- mode_t st_mode = st->st_mode;
- void * dnli = dnlInitIterator(fsm, 0);
- char * dn = fsm->rdbuf;
- int dc = dnlCount(dnli);
-
- fsm->path = NULL;
- dn[0] = '\0';
- fsm->dnlx = (dc ? xcalloc(dc, sizeof(*fsm->dnlx)) : NULL);
- while ((fsm->path = dnlNextIterator(dnli)) != NULL) {
- int dnlen = strlen(fsm->path);
- char * te;
-
- dc = dnlIndex(dnli);
- if (dc < 0) continue;
- fsm->dnlx[dc] = dnlen;
- if (dnlen <= 1)
- continue;
- if (dnlen <= fsm->ldnlen && !strcmp(fsm->path, fsm->ldn))
- continue;
-
- /* Copy to avoid const on fsm->path. */
- (void) stpcpy(dn, fsm->path);
- fsm->path = dn;
-
- /* Initial mode for created dirs is 0700 */
- st->st_mode &= ~07777; /* XXX abuse st->st_mode */
- st->st_mode |= 00700;
-
- /* Assume '/' directory, otherwise "mkdir -p" */
- for (i = 1, te = dn + 1; *te; te++, i++) {
- if (*te != '/') continue;
-
- *te = '\0';
-
- /* Already validated? */
- if (i < fsm->ldnlen &&
- (fsm->ldn[i] == '/' || fsm->ldn[i] == '\0') &&
- !strncmp(fsm->path, fsm->ldn, i))
- {
- *te = '/';
- /* Move pre-existing path marker forward. */
- fsm->dnlx[dc] = (te - dn);
- continue;
- }
-
- /* Validate next component of path. */
- rc = fsmStage(fsm, FSM_LSTAT);
- *te = '/';
-
- /* Directory already exists? */
- if (rc == 0 && S_ISDIR(ost->st_mode)) {
- /* Move pre-existing path marker forward. */
- fsm->dnlx[dc] = (te - dn);
- } else if (rc == CPIOERR_LSTAT_FAILED) {
- TFI_t fi = fsmGetFi(fsm);
- mode_t st_mode = st->st_mode;
- *te = '\0';
- st->st_mode = S_IFDIR | (fi->dperms & 07777);
- rc = fsmStage(fsm, FSM_MKDIR);
- if (!rc)
- rpmMessage(RPMMESS_WARNING,
- _("%s directory created with perms %04o.\n"),
- fsm->path, (st->st_mode & 07777));
- *te = '/';
- st->st_mode = st_mode;
- }
- if (rc) break;
- }
- if (rc) break;
-
- /* Save last validated path. */
- if (fsm->ldnalloc < (dnlen + 1)) {
- fsm->ldnalloc = dnlen + 100;
- fsm->ldn = xrealloc(fsm->ldn, fsm->ldnalloc);
- }
- strcpy(fsm->ldn, fsm->path);
- fsm->ldnlen = dnlen;
- }
- dnli = dnlFreeIterator(dnli);
- fsm->path = path;
- st->st_mode = st_mode; /* XXX restore st->st_mode */
- }
- break;
- case FSM_RMDIRS:
- if (fsm->dnlx) {
- const char * path = fsm->path;
- void * dnli = dnlInitIterator(fsm, 1);
- char * dn = fsm->rdbuf;
- int dc = dnlCount(dnli);
-
- fsm->path = NULL;
- dn[0] = '\0';
- while ((fsm->path = dnlNextIterator(dnli)) != NULL) {
- int dnlen = strlen(fsm->path);
- char * te;
-
- dc = dnlIndex(dnli);
- if (fsm->dnlx[dc] < 1 || fsm->dnlx[dc] >= dnlen)
- continue;
-
- /* Copy to avoid const on fsm->path. */
- te = stpcpy(dn, fsm->path) - 1;
- fsm->path = dn;
-
- /* Remove generated directories. */
- do {
- if (*te == '/') {
- *te = '\0';
- rc = fsmStage(fsm, FSM_RMDIR);
- *te = '/';
- }
- if (rc) break;
- te--;
- } while ((te - dn) > fsm->dnlx[dc]);
- }
- dnli = dnlFreeIterator(dnli);
- fsm->path = path;
- }
- break;
- case FSM_PROCESS:
- if (fsm->postpone) {
- if (fsm->goal == FSM_PKGINSTALL)
- rc = fsmStage(fsm, FSM_EAT);
- break;
- }
-
- if (fsm->goal == FSM_PKGBUILD) {
- if (!S_ISDIR(st->st_mode) && st->st_nlink > 1) {
- struct hardLink * li, * prev;
- rc = writeLinkedFile(fsm);
- if (rc) break; /* W2DO? */
-
- for (li = fsm->links, prev = NULL; li; prev = li, li = li->next)
- if (li == fsm->li) break;
-
- if (prev == NULL)
- fsm->links = fsm->li->next;
- else
- prev->next = fsm->li->next;
- fsm->li->next = NULL;
- fsm->li = freeHardLink(fsm->li);
- } else {
- rc = writeFile(fsm, 1);
- }
- break;
- }
-
- if (fsm->goal != FSM_PKGINSTALL)
- break;
-
- if (S_ISREG(st->st_mode)) {
- const char * path = fsm->path;
- if (fsm->osuffix)
- fsm->path = fsmFsPath(fsm, st, NULL, NULL);
- rc = fsmStage(fsm, FSM_VERIFY);
-
- if (rc == 0 && fsm->osuffix) {
- const char * opath = fsm->opath;
- fsm->opath = fsm->path;
- fsm->path = fsmFsPath(fsm, st, NULL, fsm->osuffix);
- rc = fsmStage(fsm, FSM_RENAME);
- if (!rc)
- rpmMessage(RPMMESS_WARNING,
- _("%s saved as %s\n"), fsm->opath, fsm->path);
- fsm->path = _free(fsm->path);
- fsm->opath = opath;
- }
-
- fsm->path = path;
- if (rc != CPIOERR_LSTAT_FAILED) return rc;
- rc = expandRegular(fsm);
- } else if (S_ISDIR(st->st_mode)) {
- mode_t st_mode = st->st_mode;
- rc = fsmStage(fsm, FSM_VERIFY);
- if (rc == CPIOERR_LSTAT_FAILED) {
- st->st_mode &= ~07777; /* XXX abuse st->st_mode */
- st->st_mode |= 00700;
- rc = fsmStage(fsm, FSM_MKDIR);
- st->st_mode = st_mode; /* XXX restore st->st_mode */
- }
- } else if (S_ISLNK(st->st_mode)) {
- const char * opath = fsm->opath;
-
- if ((st->st_size + 1) > fsm->rdsize) {
- rc = CPIOERR_HDR_SIZE;
- break;
- }
-
- fsm->wrlen = st->st_size;
- rc = fsmStage(fsm, FSM_DREAD);
- if (!rc && fsm->rdnb != fsm->wrlen)
- rc = CPIOERR_READ_FAILED;
- if (rc) break;
-
- fsm->wrbuf[st->st_size] = '\0';
- /* XXX symlink(fsm->opath, fsm->path) */
- fsm->opath = fsm->wrbuf; /* XXX abuse fsm->path */
- rc = fsmStage(fsm, FSM_VERIFY);
- if (rc == CPIOERR_LSTAT_FAILED)
- rc = fsmStage(fsm, FSM_SYMLINK);
- fsm->opath = opath; /* XXX restore fsm->path */
- } else if (S_ISFIFO(st->st_mode)) {
- mode_t st_mode = st->st_mode;
- /* This mimics cpio S_ISSOCK() behavior but probably isnt' right */
- rc = fsmStage(fsm, FSM_VERIFY);
- if (rc == CPIOERR_LSTAT_FAILED) {
- st->st_mode = 0000; /* XXX abuse st->st_mode */
- rc = fsmStage(fsm, FSM_MKFIFO);
- st->st_mode = st_mode; /* XXX restore st->st_mode */
- }
- } else if (S_ISCHR(st->st_mode) ||
- S_ISBLK(st->st_mode) ||
- S_ISSOCK(st->st_mode))
- {
- rc = fsmStage(fsm, FSM_VERIFY);
- if (rc == CPIOERR_LSTAT_FAILED)
- rc = fsmStage(fsm, FSM_MKNOD);
- } else {
- rc = CPIOERR_UNKNOWN_FILETYPE;
- }
- if (!S_ISDIR(st->st_mode) && st->st_nlink > 1) {
- fsm->li->createdPath = fsm->li->linkIndex;
- rc = fsmMakeLinks(fsm);
- }
- break;
- case FSM_POST:
- break;
- case FSM_MKLINKS:
- break;
- case FSM_NOTIFY: /* XXX move from fsm to psm -> tsm */
- if (fsm->goal == FSM_PKGINSTALL || fsm->goal == FSM_PKGBUILD) {
- rpmTransactionSet ts = fsmGetTs(fsm);
- TFI_t fi = fsmGetFi(fsm);
- if (ts && ts->notify && fi)
- (void)ts->notify(fi->h, RPMCALLBACK_INST_PROGRESS,
- fdGetCpioPos(fsm->cfd), fi->archiveSize,
- (fi->ap ? fi->ap->key : NULL), ts->notifyData);
- }
- break;
- case FSM_UNDO:
- if (fsm->postpone)
- break;
- if (fsm->goal == FSM_PKGINSTALL) {
- (void) fsmStage(fsm,
- (S_ISDIR(st->st_mode) ? FSM_RMDIR : FSM_UNLINK));
-
-#ifdef NOTYET /* XXX remove only dirs just created, not all. */
- if (fsm->dnlx)
- (void) fsmStage(fsm, FSM_RMDIRS);
-#endif
- errno = saveerrno;
- }
- if (fsm->failedFile && *fsm->failedFile == NULL)
- *fsm->failedFile = xstrdup(fsm->path);
- break;
- case FSM_FINI:
- if (!fsm->postpone && fsm->commit) {
- if (fsm->goal == FSM_PKGINSTALL)
- rc = ((!S_ISDIR(st->st_mode) && st->st_nlink > 1)
- ? fsmCommitLinks(fsm) : fsmStage(fsm, FSM_COMMIT));
- if (fsm->goal == FSM_PKGCOMMIT)
- rc = fsmStage(fsm, FSM_COMMIT);
- if (fsm->goal == FSM_PKGERASE)
- rc = fsmStage(fsm, FSM_COMMIT);
- }
- fsm->path = _free(fsm->path);
- fsm->opath = _free(fsm->opath);
- memset(st, 0, sizeof(*st));
- memset(ost, 0, sizeof(*ost));
- break;
- case FSM_COMMIT:
- /* Rename pre-existing modified or unmanaged file. */
- if (fsm->diskchecked && fsm->exists && fsm->osuffix) {
- const char * opath = fsm->opath;
- const char * path = fsm->path;
- fsm->opath = fsmFsPath(fsm, st, NULL, NULL);
- fsm->path = fsmFsPath(fsm, st, NULL, fsm->osuffix);
- rc = fsmStage(fsm, FSM_RENAME);
- if (!rc) {
- rpmMessage(RPMMESS_WARNING, _("%s saved as %s\n"),
- fsm->opath, fsm->path);
- }
- fsm->path = _free(fsm->path);
- fsm->path = path;
- fsm->opath = _free(fsm->opath);
- fsm->opath = opath;
- }
-
- /* Remove erased files. */
- if (fsm->goal == FSM_PKGERASE) {
- if (fsm->action == FA_ERASE) {
- TFI_t fi = fsmGetFi(fsm);
- if (S_ISDIR(st->st_mode)) {
- rc = fsmStage(fsm, FSM_RMDIR);
- if (!rc) break;
- switch (errno) {
- case ENOENT: /* XXX rmdir("/") linux 2.2.x kernel hack */
- case ENOTEMPTY:
- /* XXX make sure that build side permits %missingok on directories. */
- if (fsm->fflags & RPMFILE_MISSINGOK)
- break;
-
- /* XXX common error message. */
- rpmError(RPMERR_RMDIR,
- _("%s rmdir of %s failed: Directory not empty\n"),
- fiTypeString(fi), fsm->path);
- break;
- default:
- rpmError(RPMERR_RMDIR,
- _("%s rmdir of %s failed: %s\n"),
- fiTypeString(fi), fsm->path, strerror(errno));
- break;
- }
- } else {
- rc = fsmStage(fsm, FSM_UNLINK);
- if (!rc) break;
- if (!(errno == ENOENT && (fsm->fflags & RPMFILE_MISSINGOK)))
- rpmError(RPMERR_UNLINK,
- _("%s unlink of %s failed: %s\n"),
- fiTypeString(fi), fsm->path, strerror(errno));
- }
- }
- break;
- }
-
- if (!S_ISSOCK(st->st_mode)) { /* XXX /dev/log et al are skipped */
- /* Rename temporary to final file name. */
- if (!S_ISDIR(st->st_mode) &&
- (fsm->subdir || fsm->suffix || fsm->nsuffix))
- {
- fsm->opath = fsm->path;
- fsm->path = fsmFsPath(fsm, st, NULL, fsm->nsuffix);
- rc = fsmStage(fsm, FSM_RENAME);
- if (!rc && fsm->nsuffix) {
- const char * opath = fsmFsPath(fsm, st, NULL, NULL);
- rpmMessage(RPMMESS_WARNING, _("%s created as %s\n"),
- opath, fsm->path);
- opath = _free(opath);
- }
- fsm->opath = _free(fsm->opath);
- }
- if (S_ISLNK(st->st_mode)) {
- if (!rc && !getuid())
- rc = fsmStage(fsm, FSM_LCHOWN);
- } else {
- if (!rc && !getuid())
- rc = fsmStage(fsm, FSM_CHOWN);
- if (!rc)
- rc = fsmStage(fsm, FSM_CHMOD);
- if (!rc) {
- time_t st_mtime = st->st_mtime;
- TFI_t fi = fsmGetFi(fsm);
- if (fi->fmtimes)
- st->st_mtime = fi->fmtimes[fsm->ix];
- rc = fsmStage(fsm, FSM_UTIME);
- st->st_mtime = st_mtime;
- }
- }
- }
-
- /* Notify on success. */
- if (!rc) rc = fsmStage(fsm, FSM_NOTIFY);
- break;
- case FSM_DESTROY:
- fsm->path = _free(fsm->path);
-
- /* Create any remaining links (if no error), and clean up. */
- while ((fsm->li = fsm->links) != NULL) {
- fsm->links = fsm->li->next;
- fsm->li->next = NULL;
- if (fsm->goal == FSM_PKGINSTALL && fsm->commit && fsm->li->linksLeft)
- {
- for (i = 0 ; i < fsm->li->linksLeft; i++) {
- if (fsm->li->filex[i] < 0) continue;
- rc = CPIOERR_MISSING_HARDLINK;
- if (fsm->failedFile && *fsm->failedFile == NULL) {
- fsm->ix = fsm->li->filex[i];
- if (!fsmStage(fsm, FSM_MAP)) {
- *fsm->failedFile = fsm->path;
- fsm->path = NULL;
- }
- }
- break;
- }
- }
- if (fsm->goal == FSM_PKGBUILD) {
- rc = CPIOERR_MISSING_HARDLINK;
- }
- fsm->li = freeHardLink(fsm->li);
- }
- fsm->ldn = _free(fsm->ldn);
- fsm->ldnalloc = fsm->ldnlen = 0;
- fsm->rdbuf = fsm->rdb = _free(fsm->rdb);
- fsm->wrbuf = fsm->wrb = _free(fsm->wrb);
- break;
- case FSM_VERIFY:
- if (fsm->diskchecked && !fsm->exists) {
- rc = CPIOERR_LSTAT_FAILED;
- break;
- }
- if (S_ISREG(st->st_mode)) {
- char * path = alloca(strlen(fsm->path) + sizeof("-RPMDELETE"));
- (void) stpcpy( stpcpy(path, fsm->path), "-RPMDELETE");
- /*
- * XXX HP-UX (and other os'es) don't permit unlink on busy
- * XXX files.
- */
- fsm->opath = fsm->path;
- fsm->path = path;
- rc = fsmStage(fsm, FSM_RENAME);
- if (!rc)
- (void) fsmStage(fsm, FSM_UNLINK);
- else
- rc = CPIOERR_UNLINK_FAILED;
- fsm->path = fsm->opath;
- fsm->opath = NULL;
- return (rc ? rc : CPIOERR_LSTAT_FAILED); /* XXX HACK */
- /*@notreached@*/ break;
- } else if (S_ISDIR(st->st_mode)) {
- if (S_ISDIR(ost->st_mode)) return 0;
- if (S_ISLNK(ost->st_mode)) {
- rc = fsmStage(fsm, FSM_STAT);
- if (rc == CPIOERR_STAT_FAILED && errno == ENOENT) rc = 0;
- if (rc) break;
- errno = saveerrno;
- if (S_ISDIR(ost->st_mode)) return 0;
- }
- } else if (S_ISLNK(st->st_mode)) {
- if (S_ISLNK(ost->st_mode)) {
- /* XXX NUL terminated result in fsm->rdbuf, len in fsm->rdnb. */
- rc = fsmStage(fsm, FSM_READLINK);
- errno = saveerrno;
- if (rc) break;
- if (!strcmp(fsm->opath, fsm->rdbuf)) return 0;
- }
- } else if (S_ISFIFO(st->st_mode)) {
- if (S_ISFIFO(ost->st_mode)) return 0;
- } else if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
- if ((S_ISCHR(ost->st_mode) || S_ISBLK(ost->st_mode)) &&
- (ost->st_rdev == st->st_rdev)) return 0;
- } else if (S_ISSOCK(st->st_mode)) {
- if (S_ISSOCK(ost->st_mode)) return 0;
- }
- /* XXX shouldn't do this with commit/undo. */
- rc = 0;
- if (fsm->stage == FSM_PROCESS) rc = fsmStage(fsm, FSM_UNLINK);
- if (rc == 0) rc = CPIOERR_LSTAT_FAILED;
- return (rc ? rc : CPIOERR_LSTAT_FAILED); /* XXX HACK */
- /*@notreached@*/ break;
-
- case FSM_UNLINK:
- rc = Unlink(fsm->path);
- if (_fsm_debug && (stage & FSM_SYSCALL))
- rpmMessage(RPMMESS_DEBUG, " %8s (%s) %s\n", cur,
- fsm->path, (rc < 0 ? strerror(errno) : ""));
- if (rc < 0) rc = CPIOERR_UNLINK_FAILED;
- break;
- case FSM_RENAME:
- rc = Rename(fsm->opath, fsm->path);
- if (_fsm_debug && (stage & FSM_SYSCALL))
- rpmMessage(RPMMESS_DEBUG, " %8s (%s, %s) %s\n", cur,
- fsm->opath, fsm->path, (rc < 0 ? strerror(errno) : ""));
- if (rc < 0) rc = CPIOERR_RENAME_FAILED;
- break;
- case FSM_MKDIR:
- rc = Mkdir(fsm->path, (st->st_mode & 07777));
- if (_fsm_debug && (stage & FSM_SYSCALL))
- rpmMessage(RPMMESS_DEBUG, " %8s (%s, 0%04o) %s\n", cur,
- fsm->path, (st->st_mode & 07777),
- (rc < 0 ? strerror(errno) : ""));
- if (rc < 0) rc = CPIOERR_MKDIR_FAILED;
- break;
- case FSM_RMDIR:
- rc = Rmdir(fsm->path);
- if (_fsm_debug && (stage & FSM_SYSCALL))
- rpmMessage(RPMMESS_DEBUG, " %8s (%s) %s\n", cur,
- fsm->path, (rc < 0 ? strerror(errno) : ""));
- if (rc < 0) rc = CPIOERR_RMDIR_FAILED;
- break;
- case FSM_CHOWN:
- rc = chown(fsm->path, st->st_uid, st->st_gid);
- if (_fsm_debug && (stage & FSM_SYSCALL))
- rpmMessage(RPMMESS_DEBUG, " %8s (%s, %d, %d) %s\n", cur,
- fsm->path, st->st_uid, st->st_gid,
- (rc < 0 ? strerror(errno) : ""));
- if (rc < 0) rc = CPIOERR_CHOWN_FAILED;
- break;
- case FSM_LCHOWN:
-#if ! CHOWN_FOLLOWS_SYMLINK
- rc = lchown(fsm->path, st->st_uid, st->st_gid);
- if (_fsm_debug && (stage & FSM_SYSCALL))
- rpmMessage(RPMMESS_DEBUG, " %8s (%s, %d, %d) %s\n", cur,
- fsm->path, st->st_uid, st->st_gid,
- (rc < 0 ? strerror(errno) : ""));
- if (rc < 0) rc = CPIOERR_CHOWN_FAILED;
-#endif
- break;
- case FSM_CHMOD:
- rc = chmod(fsm->path, (st->st_mode & 07777));
- if (_fsm_debug && (stage & FSM_SYSCALL))
- rpmMessage(RPMMESS_DEBUG, " %8s (%s, 0%04o) %s\n", cur,
- fsm->path, (st->st_mode & 07777),
- (rc < 0 ? strerror(errno) : ""));
- if (rc < 0) rc = CPIOERR_CHMOD_FAILED;
- break;
- case FSM_UTIME:
- { struct utimbuf stamp;
- stamp.actime = st->st_mtime;
- stamp.modtime = st->st_mtime;
- rc = utime(fsm->path, &stamp);
- if (_fsm_debug && (stage & FSM_SYSCALL))
- rpmMessage(RPMMESS_DEBUG, " %8s (%s, 0x%x) %s\n", cur,
- fsm->path, (unsigned)st->st_mtime,
- (rc < 0 ? strerror(errno) : ""));
- if (rc < 0) rc = CPIOERR_UTIME_FAILED;
- }
- break;
- case FSM_SYMLINK:
- rc = symlink(fsm->opath, fsm->path);
- if (_fsm_debug && (stage & FSM_SYSCALL))
- rpmMessage(RPMMESS_DEBUG, " %8s (%s, %s) %s\n", cur,
- fsm->opath, fsm->path, (rc < 0 ? strerror(errno) : ""));
- if (rc < 0) rc = CPIOERR_SYMLINK_FAILED;
- break;
- case FSM_LINK:
- rc = Link(fsm->opath, fsm->path);
- if (_fsm_debug && (stage & FSM_SYSCALL))
- rpmMessage(RPMMESS_DEBUG, " %8s (%s, %s) %s\n", cur,
- fsm->opath, fsm->path, (rc < 0 ? strerror(errno) : ""));
- if (rc < 0) rc = CPIOERR_LINK_FAILED;
- break;
- case FSM_MKFIFO:
- rc = mkfifo(fsm->path, (st->st_mode & 07777));
- if (_fsm_debug && (stage & FSM_SYSCALL))
- rpmMessage(RPMMESS_DEBUG, " %8s (%s, 0%04o) %s\n", cur,
- fsm->path, (st->st_mode & 07777),
- (rc < 0 ? strerror(errno) : ""));
- if (rc < 0) rc = CPIOERR_MKFIFO_FAILED;
- break;
- case FSM_MKNOD:
- /*@-unrecog@*/
- rc = mknod(fsm->path, (st->st_mode & ~07777), st->st_rdev);
- if (_fsm_debug && (stage & FSM_SYSCALL))
- rpmMessage(RPMMESS_DEBUG, " %8s (%s, 0%o, 0x%x) %s\n", cur,
- fsm->path, (st->st_mode & ~07777), (unsigned)st->st_rdev,
- (rc < 0 ? strerror(errno) : ""));
- if (rc < 0) rc = CPIOERR_MKNOD_FAILED;
- /*@=unrecog@*/
- break;
- case FSM_LSTAT:
- rc = Lstat(fsm->path, ost);
- if (_fsm_debug && (stage & FSM_SYSCALL) && rc && errno != ENOENT)
- rpmMessage(RPMMESS_DEBUG, " %8s (%s, ost) %s\n", cur,
- fsm->path, (rc < 0 ? strerror(errno) : ""));
- if (rc < 0) rc = CPIOERR_LSTAT_FAILED;
- break;
- case FSM_STAT:
- rc = Stat(fsm->path, ost);
- if (_fsm_debug && (stage & FSM_SYSCALL) && rc && errno != ENOENT)
- rpmMessage(RPMMESS_DEBUG, " %8s (%s, ost) %s\n", cur,
- fsm->path, (rc < 0 ? strerror(errno) : ""));
- if (rc < 0) rc = CPIOERR_STAT_FAILED;
- break;
- case FSM_READLINK:
- /* XXX NUL terminated result in fsm->rdbuf, len in fsm->rdnb. */
- rc = Readlink(fsm->path, fsm->rdbuf, fsm->rdsize - 1);
- if (_fsm_debug && (stage & FSM_SYSCALL))
- rpmMessage(RPMMESS_DEBUG, " %8s (%s, rdbuf, %d) %s\n", cur,
- fsm->path, fsm->rdlen, (rc < 0 ? strerror(errno) : ""));
- if (rc < 0) rc = CPIOERR_READLINK_FAILED;
- else {
- fsm->rdnb = rc;
- fsm->rdbuf[fsm->rdnb] = '\0';
- rc = 0;
- }
- break;
- case FSM_CHROOT:
- break;
-
- case FSM_NEXT:
- rc = fsmStage(fsm, FSM_HREAD);
- if (rc) break;
- if (!strcmp(fsm->path, CPIO_TRAILER)) { /* Detect end-of-payload. */
- fsm->path = _free(fsm->path);
- rc = CPIOERR_HDR_TRAILER;
- }
- if (!rc)
- rc = fsmStage(fsm, FSM_POS);
- break;
- case FSM_EAT:
- for (left = st->st_size; left > 0; left -= fsm->rdnb) {
- fsm->wrlen = (left > fsm->wrsize ? fsm->wrsize : left);
- rc = fsmStage(fsm, FSM_DREAD);
- if (rc) break;
- }
- break;
- case FSM_POS:
- left = (modulo - (fdGetCpioPos(fsm->cfd) % modulo)) % modulo;
- if (left) {
- fsm->wrlen = left;
- (void) fsmStage(fsm, FSM_DREAD);
- }
- break;
- case FSM_PAD:
- left = (modulo - (fdGetCpioPos(fsm->cfd) % modulo)) % modulo;
- if (left) {
- memset(fsm->rdbuf, 0, left);
- /* XXX DWRITE uses rdnb for I/O length. */
- fsm->rdnb = left;
- (void) fsmStage(fsm, FSM_DWRITE);
- }
- break;
- case FSM_TRAILER:
- rc = cpioTrailerWrite(fsm);
- break;
- case FSM_HREAD:
- rc = fsmStage(fsm, FSM_POS);
- if (!rc)
- rc = cpioHeaderRead(fsm, st); /* Read next payload header. */
- break;
- case FSM_HWRITE:
- rc = cpioHeaderWrite(fsm, st); /* Write next payload header. */
- break;
- case FSM_DREAD:
- fsm->rdnb = Fread(fsm->wrbuf, sizeof(*fsm->wrbuf), fsm->wrlen, fsm->cfd);
- if (_fsm_debug && (stage & FSM_SYSCALL))
- rpmMessage(RPMMESS_DEBUG, " %8s (%s, %d, cfd)\trdnb %d\n",
- cur, (fsm->wrbuf == fsm->wrb ? "wrbuf" : "mmap"),
- fsm->wrlen, fsm->rdnb);
-if (fsm->rdnb != fsm->wrlen) fprintf(stderr, "*** short read, had %d, got %d\n", (int)fsm->rdnb, (int)fsm->wrlen);
-#ifdef NOTYET
- if (Ferror(fsm->rfd))
- rc = CPIOERR_READ_FAILED;
-#endif
- if (fsm->rdnb > 0)
- fdSetCpioPos(fsm->cfd, fdGetCpioPos(fsm->cfd) + fsm->rdnb);
- break;
- case FSM_DWRITE:
- fsm->wrnb = Fwrite(fsm->rdbuf, sizeof(*fsm->rdbuf), fsm->rdnb, fsm->cfd);
- if (_fsm_debug && (stage & FSM_SYSCALL))
- rpmMessage(RPMMESS_DEBUG, " %8s (%s, %d, cfd)\twrnb %d\n",
- cur, (fsm->rdbuf == fsm->rdb ? "rdbuf" : "mmap"),
- fsm->rdnb, fsm->wrnb);
-if (fsm->rdnb != fsm->wrnb) fprintf(stderr, "*** short write, had %d, got %d\n", (int)fsm->rdnb, (int)fsm->wrnb);
-#ifdef NOTYET
- if (Ferror(fsm->wfd))
- rc = CPIOERR_WRITE_FAILED;
-#endif
- if (fsm->wrnb > 0)
- fdSetCpioPos(fsm->cfd, fdGetCpioPos(fsm->cfd) + fsm->wrnb);
- break;
-
- case FSM_ROPEN:
- fsm->rfd = Fopen(fsm->path, "r.ufdio");
- if (fsm->rfd == NULL || Ferror(fsm->rfd)) {
- if (fsm->rfd) (void) fsmStage(fsm, FSM_RCLOSE);
- fsm->rfd = NULL;
- rc = CPIOERR_OPEN_FAILED;
- break;
- }
- if (_fsm_debug && (stage & FSM_SYSCALL))
- rpmMessage(RPMMESS_DEBUG, " %8s (%s, \"r\") rfd %p rdbuf %p\n", cur,
- fsm->path, fsm->rfd, fsm->rdbuf);
- break;
- case FSM_READ:
- fsm->rdnb = Fread(fsm->rdbuf, sizeof(*fsm->rdbuf), fsm->rdlen, fsm->rfd);
- if (_fsm_debug && (stage & FSM_SYSCALL))
- rpmMessage(RPMMESS_DEBUG, " %8s (rdbuf, %d, rfd)\trdnb %d\n",
- cur, fsm->rdlen, fsm->rdnb);
-if (fsm->rdnb != fsm->rdlen) fprintf(stderr, "*** short read, had %d, got %d\n", (int)fsm->rdnb, (int)fsm->rdlen);
-#ifdef NOTYET
- if (Ferror(fsm->rfd))
- rc = CPIOERR_READ_FAILED;
-#endif
- break;
- case FSM_RCLOSE:
- if (fsm->rfd) {
- if (_fsm_debug && (stage & FSM_SYSCALL))
- rpmMessage(RPMMESS_DEBUG, " %8s (%p)\n", cur, fsm->rfd);
- (void) Fclose(fsm->rfd);
- errno = saveerrno;
- }
- fsm->rfd = NULL;
- break;
- case FSM_WOPEN:
- fsm->wfd = Fopen(fsm->path, "w.ufdio");
- if (fsm->wfd == NULL || Ferror(fsm->wfd)) {
- if (fsm->wfd) (void) fsmStage(fsm, FSM_WCLOSE);
- fsm->wfd = NULL;
- rc = CPIOERR_OPEN_FAILED;
- }
- if (_fsm_debug && (stage & FSM_SYSCALL))
- rpmMessage(RPMMESS_DEBUG, " %8s (%s, \"w\") wfd %p wrbuf %p\n", cur,
- fsm->path, fsm->wfd, fsm->wrbuf);
- break;
- case FSM_WRITE:
- fsm->wrnb = Fwrite(fsm->wrbuf, sizeof(*fsm->wrbuf), fsm->rdnb, fsm->wfd);
- if (_fsm_debug && (stage & FSM_SYSCALL))
- rpmMessage(RPMMESS_DEBUG, " %8s (wrbuf, %d, wfd)\twrnb %d\n",
- cur, fsm->rdnb, fsm->wrnb);
-if (fsm->rdnb != fsm->wrnb) fprintf(stderr, "*** short write: had %d, got %d\n", (int)fsm->rdnb, (int)fsm->wrnb);
-#ifdef NOTYET
- if (Ferror(fsm->wfd))
- rc = CPIOERR_WRITE_FAILED;
-#endif
- break;
- case FSM_WCLOSE:
- if (fsm->wfd) {
- if (_fsm_debug && (stage & FSM_SYSCALL))
- rpmMessage(RPMMESS_DEBUG, " %8s (%p)\n", cur, fsm->wfd);
- (void) Fclose(fsm->wfd);
- errno = saveerrno;
- }
- fsm->wfd = NULL;
- break;
-
- default:
- break;
- }
-
- if (!(stage & FSM_INTERNAL)) {
- fsm->rc = (rc == CPIOERR_HDR_TRAILER ? 0 : rc);
- }
- return rc;
-}
-
const char *const cpioStrerror(int rc)
{
static char msg[256];
--- /dev/null
+/** \ingroup payload
+ * \file lib/fsm.c
+ * Handle payloads within rpm packages.
+ */
+
+#include "system.h"
+
+#include "psm.h"
+#include "rpmerr.h"
+#include "debug.h"
+
+/*@access FD_t @*/
+/*@access rpmTransactionSet @*/
+/*@access TFI_t @*/
+/*@access FSM_t @*/
+
+#define alloca_strdup(_s) strcpy(alloca(strlen(_s)+1), (_s))
+
+/**
+ * Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
+ * @param this memory to free
+ * @retval NULL always
+ */
+static /*@null@*/ void * _free(/*@only@*/ /*@null@*/ const void * this) {
+ if (this) free((void *)this);
+ return NULL;
+}
+
+int _fsm_debug = 0;
+
+rpmTransactionSet fsmGetTs(const FSM_t fsm) {
+ const FSMI_t iter = fsm->iter;
+ return (iter ? iter->ts : NULL);
+}
+
+TFI_t fsmGetFi(const FSM_t fsm) {
+ const FSMI_t iter = fsm->iter;
+ return (iter ? iter->fi : NULL);
+}
+
+#define SUFFIX_RPMORIG ".rpmorig"
+#define SUFFIX_RPMSAVE ".rpmsave"
+#define SUFFIX_RPMNEW ".rpmnew"
+
+/** \ingroup payload
+ * Build path to file from file info, ornamented with subdir and suffix.
+ * @param fsm file state machine data
+ * @param st file stat info
+ * @param subdir subdir to use (NULL disables)
+ * @param suffix suffix to use (NULL disables)
+ * @retval path to file
+ */
+static /*@only@*//*@null@*/ const char * fsmFsPath(/*@null@*/ const FSM_t fsm,
+ /*@null@*/ const struct stat * st,
+ /*@null@*/ const char * subdir,
+ /*@null@*/ const char * suffix)
+{
+ const char * s = NULL;
+
+ if (fsm) {
+ int nb;
+ char * t;
+ nb = strlen(fsm->dirName) +
+ (st && subdir && !S_ISDIR(st->st_mode) ? strlen(subdir) : 0) +
+ (st && suffix && !S_ISDIR(st->st_mode) ? strlen(suffix) : 0) +
+ strlen(fsm->baseName) + 1;
+ s = t = xmalloc(nb);
+ t = stpcpy(t, fsm->dirName);
+ if (st && subdir && !S_ISDIR(st->st_mode))
+ t = stpcpy(t, subdir);
+ t = stpcpy(t, fsm->baseName);
+ if (st && suffix && !S_ISDIR(st->st_mode))
+ t = stpcpy(t, suffix);
+ }
+ return s;
+}
+
+/** \ingroup payload
+ * Destroy file info iterator.
+ * @retval NULL always
+ */
+static /*@null@*/ void * mapFreeIterator(/*@only@*//*@null@*/const void * this) {
+ return _free((void *)this);
+}
+
+/** \ingroup payload
+ */
+static void *
+mapInitIterator(/*@kept@*/ const void * this, /*@kept@*/ const void * that)
+{
+ rpmTransactionSet ts = (void *)this;
+ TFI_t fi = (void *)that;
+ FSMI_t iter = NULL;
+
+ iter = xcalloc(1, sizeof(*iter));
+ iter->ts = ts;
+ iter->fi = fi;
+ switch (fi->type) {
+ case TR_ADDED: iter->i = 0; break;
+ case TR_REMOVED: iter->i = fi->fc - 1; break;
+ }
+ iter->isave = iter->i;
+ return iter;
+}
+
+/** \ingroup payload
+ */
+static int mapNextIterator(void * this) {
+ FSMI_t iter = this;
+ const TFI_t fi = iter->fi;
+ int i = -1;
+
+ switch (fi->type) {
+ case TR_ADDED: if (iter->i < fi->fc) i = iter->i++; break;
+ case TR_REMOVED: if (iter->i >= 0) i = iter->i--; break;
+ }
+ iter->isave = i;
+ return i;
+}
+
+/** \ingroup payload
+ */
+typedef struct dnli_s {
+/*@dependent@*/ TFI_t fi;
+/*@only@*/ /*@null@*/ char * active;
+ int reverse;
+ int isave;
+ int i;
+} * DNLI_t;
+
+/** \ingroup payload
+ */
+static /*@null@*/ void * dnlFreeIterator(/*@only@*//*@null@*/ const void * this)
+{
+ if (this) {
+ DNLI_t dnli = (void *)this;
+ if (dnli->active) free(dnli->active);
+ }
+ return _free(this);
+}
+
+/** \ingroup payload
+ */
+static inline int dnlCount(const DNLI_t dnli) {
+ return (dnli ? dnli->fi->dc : 0);
+}
+
+/** \ingroup payload
+ */
+static inline int dnlIndex(const DNLI_t dnli) {
+ return (dnli ? dnli->isave : -1);
+}
+
+/** \ingroup payload
+ * @param fsm file state machine data
+ */
+static /*@only@*/ void * dnlInitIterator(const FSM_t fsm, int reverse)
+{
+ TFI_t fi = fsmGetFi(fsm);
+ DNLI_t dnli;
+ int i, j;
+
+ if (fi == NULL)
+ return NULL;
+ dnli = xcalloc(1, sizeof(*dnli));
+ dnli->fi = fi;
+ dnli->reverse = reverse;
+ dnli->i = (reverse ? fi->dc : 0);
+
+ if (fi->dc) {
+ dnli->active = xcalloc(fi->dc, sizeof(*dnli->active));
+
+ /* Identify parent directories not skipped. */
+ for (i = 0; i < fi->fc; i++)
+ if (!XFA_SKIPPING(fi->actions[i])) dnli->active[fi->dil[i]] = 1;
+
+ /* Exclude parent directories that are explicitly included. */
+ for (i = 0; i < fi->fc; i++) {
+ int dil, dnlen, bnlen;
+
+ if (!S_ISDIR(fi->fmodes[i]))
+ continue;
+
+ dil = fi->dil[i];
+ dnlen = strlen(fi->dnl[dil]);
+ bnlen = strlen(fi->bnl[i]);
+
+ for (j = 0; j < fi->dc; j++) {
+ const char * dnl;
+ int jlen;
+
+ if (!dnli->active[j] || j == dil) continue;
+ dnl = fi->dnl[j];
+ jlen = strlen(dnl);
+ if (jlen != (dnlen+bnlen+1)) continue;
+ if (strncmp(dnl, fi->dnl[dil], dnlen)) continue;
+ if (strncmp(dnl+dnlen, fi->bnl[i], bnlen)) continue;
+ if (dnl[dnlen+bnlen] != '/' || dnl[dnlen+bnlen+1] != '\0')
+ continue;
+ /* This directory is included in the package. */
+ dnli->active[j] = 0;
+ break;
+ }
+ }
+
+ /* Print only once per package. */
+ if (!reverse) {
+ j = 0;
+ for (i = 0; i < fi->dc; i++) {
+ if (!dnli->active[i]) continue;
+ if (j == 0) {
+ j = 1;
+ rpmMessage(RPMMESS_DEBUG,
+ _("========= Directories not explictly included in package:\n"));
+ }
+ rpmMessage(RPMMESS_DEBUG, _("%9d %s\n"), i, fi->dnl[i]);
+ }
+ if (j)
+ rpmMessage(RPMMESS_DEBUG, "=========\n");
+ }
+ }
+ return dnli;
+}
+
+/** \ingroup payload
+ */
+static const char * dnlNextIterator(/*@null@*/ DNLI_t dnli) {
+ const char * dn = NULL;
+
+ if (dnli && dnli->active) {
+ TFI_t fi = dnli->fi;
+ int i = -1;
+
+ do {
+ i = (!dnli->reverse ? dnli->i++ : --dnli->i);
+ } while (i >= 0 && i < fi->dc && !dnli->active[i]);
+
+ if (i >= 0 && i < fi->dc)
+ dn = fi->dnl[i];
+ else
+ i = -1;
+ dnli->isave = i;
+ }
+ return dn;
+}
+
+/** \ingroup payload
+ */
+static int cpioStrCmp(const void * a, const void * b) {
+ const char * afn = *(const char **)a;
+ const char * bfn = *(const char **)b;
+
+ /* Match rpm-4.0 payloads with ./ prefixes. */
+ if (afn[0] == '.' && afn[1] == '/') afn += 2;
+ if (bfn[0] == '.' && bfn[1] == '/') bfn += 2;
+
+ /* If either path is absolute, make it relative. */
+ if (afn[0] == '/') afn += 1;
+ if (bfn[0] == '/') bfn += 1;
+
+ return strcmp(afn, bfn);
+}
+
+/** \ingroup payload
+ */
+static int mapFind(void * this, const char * fsmPath) {
+ FSMI_t iter = this;
+ const TFI_t fi = iter->fi;
+ int ix = -1;
+
+ if (fi) {
+ const char ** p;
+
+ p = bsearch(&fsmPath, fi->apath, fi->fc, sizeof(fsmPath), cpioStrCmp);
+ if (p == NULL) {
+ fprintf(stderr, "*** not mapped %s\n", fsmPath);
+ } else {
+ iter->i = p - fi->apath;
+ ix = mapNextIterator(iter);
+ }
+ }
+ return ix;
+}
+
+/** \ingroup payload
+ * Save hard link in chain.
+ * @param fsm file state machine data
+ * @return Is chain only partially filled?
+ */
+static int saveHardLink(FSM_t fsm)
+{
+ struct stat * st = &fsm->sb;
+ int rc = 0;
+ int ix = -1;
+ int j;
+
+ /* Find hard link set. */
+ for (fsm->li = fsm->links; fsm->li; fsm->li = fsm->li->next) {
+ if (fsm->li->inode == st->st_ino && fsm->li->dev == st->st_dev)
+ break;
+ }
+
+ /* New hard link encountered, add new link to set. */
+ if (fsm->li == NULL) {
+ fsm->li = xcalloc(1, sizeof(*fsm->li));
+ fsm->li->next = NULL;
+ fsm->li->nlink = st->st_nlink;
+ fsm->li->dev = st->st_dev;
+ fsm->li->inode = st->st_ino;
+ fsm->li->linkIndex = -1;
+ fsm->li->createdPath = -1;
+
+ fsm->li->filex = xcalloc(st->st_nlink, sizeof(fsm->li->filex[0]));
+ memset(fsm->li->filex, -1, (st->st_nlink * sizeof(fsm->li->filex[0])));
+ fsm->li->nsuffix = xcalloc(st->st_nlink, sizeof(*fsm->li->nsuffix));
+
+ if (fsm->goal == FSM_PKGBUILD)
+ fsm->li->linksLeft = st->st_nlink;
+ if (fsm->goal == FSM_PKGINSTALL)
+ fsm->li->linksLeft = 0;
+
+ fsm->li->next = fsm->links;
+ fsm->links = fsm->li;
+ }
+
+ if (fsm->goal == FSM_PKGBUILD) --fsm->li->linksLeft;
+ fsm->li->filex[fsm->li->linksLeft] = fsm->ix;
+ /*@-observertrans@*/
+ fsm->li->nsuffix[fsm->li->linksLeft] = fsm->nsuffix;
+ /*@=observertrans@*/
+ if (fsm->goal == FSM_PKGINSTALL) fsm->li->linksLeft++;
+
+#if 0
+fprintf(stderr, "*** %p link[%d:%d] %d filex %d %s\n", fsm->li, fsm->li->linksLeft, st->st_nlink, (int)st->st_size, fsm->li->filex[fsm->li->linksLeft], fsm->li->files[fsm->li->linksLeft]);
+#endif
+
+ if (fsm->goal == FSM_PKGBUILD)
+ return (fsm->li->linksLeft > 0);
+
+ if (fsm->goal != FSM_PKGINSTALL)
+ return 0;
+
+ if (!(st->st_size || fsm->li->linksLeft == st->st_nlink))
+ return 1;
+
+ /* Here come the bits, time to choose a non-skipped file name. */
+ { TFI_t fi = fsmGetFi(fsm);
+
+ for (j = fsm->li->linksLeft - 1; j >= 0; j--) {
+ ix = fsm->li->filex[j];
+ if (ix < 0 || XFA_SKIPPING(fi->actions[ix]))
+ continue;
+ break;
+ }
+ }
+
+ /* Are all links skipped or not encountered yet? */
+ if (ix < 0 || j < 0)
+ return 1; /* XXX W2DO? */
+
+ /* Save the non-skipped file name and map index. */
+ fsm->li->linkIndex = j;
+ fsm->path = _free(fsm->path);
+ fsm->ix = ix;
+ rc = fsmStage(fsm, FSM_MAP);
+ return rc;
+}
+
+/** \ingroup payload
+ * Destroy set of hard links.
+ * @param li set of hard links
+ */
+static /*@null@*/ void * freeHardLink(/*@only@*/ /*@null@*/ struct hardLink * li)
+{
+ if (li) {
+ li->nsuffix = _free(li->nsuffix); /* XXX elements are shared */
+ li->filex = _free(li->filex);
+ }
+ return _free(li);
+}
+
+FSM_t newFSM(void) {
+ FSM_t fsm = xcalloc(1, sizeof(*fsm));
+ return fsm;
+}
+
+FSM_t freeFSM(FSM_t fsm)
+{
+ if (fsm) {
+ if (fsm->path) free((void *)fsm->path);
+ while ((fsm->li = fsm->links) != NULL) {
+ fsm->links = fsm->li->next;
+ fsm->li->next = NULL;
+ fsm->li = freeHardLink(fsm->li);
+ }
+ fsm->dnlx = _free(fsm->dnlx);
+ fsm->ldn = _free(fsm->ldn);
+ fsm->iter = mapFreeIterator(fsm->iter);
+ }
+ return _free(fsm);
+}
+
+int fsmSetup(FSM_t fsm, fileStage goal,
+ const rpmTransactionSet ts, const TFI_t fi, FD_t cfd,
+ unsigned int * archiveSize, const char ** failedFile)
+{
+ size_t pos = 0;
+ int rc;
+
+ fsm->goal = goal;
+ if (cfd) {
+ fsm->cfd = fdLink(cfd, "persist (fsm)");
+ pos = fdGetCpioPos(fsm->cfd);
+ fdSetCpioPos(fsm->cfd, 0);
+ }
+ fsm->iter = mapInitIterator(ts, fi);
+
+ if (fsm->goal == FSM_PKGINSTALL) {
+ if (ts && ts->notify) {
+ (void)ts->notify(fi->h, RPMCALLBACK_INST_START, 0, fi->archiveSize,
+ (fi->ap ? fi->ap->key : NULL), ts->notifyData);
+ }
+ }
+
+ fsm->archiveSize = archiveSize;
+ if (fsm->archiveSize)
+ *fsm->archiveSize = 0;
+ fsm->failedFile = failedFile;
+ if (fsm->failedFile)
+ *fsm->failedFile = NULL;
+
+ memset(fsm->sufbuf, 0, sizeof(fsm->sufbuf));
+ if (fsm->goal == FSM_PKGINSTALL) {
+ if (ts->id > 0)
+ sprintf(fsm->sufbuf, ";%08x", (unsigned)ts->id);
+ }
+
+ rc = fsm->rc = 0;
+ rc = fsmStage(fsm, FSM_CREATE);
+
+ rc = fsmStage(fsm, fsm->goal);
+
+ if (!rc && fsm->archiveSize)
+ *fsm->archiveSize = (fdGetCpioPos(fsm->cfd) - pos);
+
+ return rc;
+}
+
+int fsmTeardown(FSM_t fsm) {
+ int rc = fsm->rc;
+
+ if (!rc)
+ rc = fsmStage(fsm, FSM_DESTROY);
+
+ fsm->iter = mapFreeIterator(fsm->iter);
+ if (fsm->cfd) {
+ fsm->cfd = fdFree(fsm->cfd, "persist (fsm)");
+ fsm->cfd = NULL;
+ }
+ fsm->failedFile = NULL;
+ return rc;
+}
+
+int fsmMapPath(FSM_t fsm)
+{
+ TFI_t fi = fsmGetFi(fsm); /* XXX const except for fstates */
+ int rc = 0;
+ int i;
+
+ fsm->osuffix = NULL;
+ fsm->nsuffix = NULL;
+ fsm->astriplen = 0;
+ fsm->action = FA_UNKNOWN;
+ fsm->mapFlags = 0;
+
+ i = fsm->ix;
+ if (fi && i >= 0 && i < fi->fc) {
+
+ fsm->astriplen = fi->astriplen;
+ fsm->action = (fi->actions ? fi->actions[i] : fi->action);
+ fsm->fflags = (fi->fflags ? fi->fflags[i] : fi->flags);
+ fsm->mapFlags = (fi->fmapflags ? fi->fmapflags[i] : fi->mapflags);
+
+ /* src rpms have simple base name in payload. */
+ fsm->archivePath =
+ (fi->apath ? fi->apath[i] + fi->striplen : fi->bnl[i]);
+ fsm->dirName = fi->dnl[fi->dil[i]];
+ fsm->baseName = fi->bnl[i];
+
+ switch (fsm->action) {
+ case FA_SKIP:
+ break;
+ case FA_SKIPMULTILIB: /* XXX RPMFILE_STATE_MULTILIB? */
+fprintf(stderr, "*** %s:%s %s\n", fiTypeString(fi), fileActionString(fsm->action), (fsm->path ? fsm->path : ""));
+ break;
+ case FA_UNKNOWN:
+fprintf(stderr, "*** %s:%s %s\n", fiTypeString(fi), fileActionString(fsm->action), (fsm->path ? fsm->path : ""));
+ break;
+
+ case FA_CREATE:
+ assert(fi->type == TR_ADDED);
+ break;
+
+ case FA_SKIPNSTATE:
+fprintf(stderr, "*** %s:%s %s\n", fiTypeString(fi), fileActionString(fsm->action), (fsm->path ? fsm->path : ""));
+ if (fi->type == TR_ADDED)
+ fi->fstates[i] = RPMFILE_STATE_NOTINSTALLED;
+ break;
+
+ case FA_SKIPNETSHARED:
+ if (fi->type == TR_ADDED)
+ fi->fstates[i] = RPMFILE_STATE_NETSHARED;
+ break;
+
+ case FA_BACKUP:
+fprintf(stderr, "*** %s:%s %s\n", fiTypeString(fi), fileActionString(fsm->action), (fsm->path ? fsm->path : ""));
+ switch (fi->type) {
+ case TR_ADDED:
+ fsm->osuffix = SUFFIX_RPMORIG;
+ break;
+ case TR_REMOVED:
+ fsm->osuffix = SUFFIX_RPMSAVE;
+ break;
+ }
+ break;
+
+ case FA_ALTNAME:
+ assert(fi->type == TR_ADDED);
+ fsm->nsuffix = SUFFIX_RPMNEW;
+ break;
+
+ case FA_SAVE:
+fprintf(stderr, "*** %s:%s %s\n", fiTypeString(fi), fileActionString(fsm->action), (fsm->path ? fsm->path : ""));
+ assert(fi->type == TR_ADDED);
+ fsm->osuffix = SUFFIX_RPMSAVE;
+ break;
+ case FA_ERASE:
+ assert(fi->type == TR_REMOVED);
+ break;
+ default:
+fprintf(stderr, "*** %s:%s %s\n", fiTypeString(fi), fileActionString(fsm->action), (fsm->path ? fsm->path : ""));
+ break;
+ }
+
+ if ((fsm->mapFlags & CPIO_MAP_PATH) || fsm->nsuffix) {
+ const struct stat * st = &fsm->sb;
+ fsm->path = _free(fsm->path);
+ fsm->path = fsmFsPath(fsm, st, fsm->subdir,
+ (fsm->suffix ? fsm->suffix : fsm->nsuffix));
+ }
+ }
+ return rc;
+}
+
+int fsmMapAttrs(FSM_t fsm)
+{
+ struct stat * st = &fsm->sb;
+ TFI_t fi = fsmGetFi(fsm);
+ int i = fsm->ix;
+
+ if (fi && i >= 0 && i < fi->fc) {
+ mode_t perms =
+ (S_ISDIR(st->st_mode) ? fi->dperms : fi->fperms);
+ mode_t finalMode =
+ (fi->fmodes ? fi->fmodes[i] : perms);
+ uid_t finalUid =
+ (fi->fuids ? fi->fuids[i] : fi->uid); /* XXX chmod u-s */
+ gid_t finalGid =
+ (fi->fgids ? fi->fgids[i] : fi->gid); /* XXX chmod g-s */
+
+ if (fsm->mapFlags & CPIO_MAP_MODE)
+ st->st_mode = (st->st_mode & S_IFMT) | finalMode;
+ if (fsm->mapFlags & CPIO_MAP_UID)
+ st->st_uid = finalUid;
+ if (fsm->mapFlags & CPIO_MAP_GID)
+ st->st_gid = finalGid;
+
+ fsm->fmd5sum = (fi->fmd5s ? fi->fmd5s[i] : NULL);
+
+ }
+ return 0;
+}
+
+/** \ingroup payload
+ * Create file from payload stream.
+ * @todo Legacy: support brokenEndian MD5 checks?
+ * @param fsm file state machine data
+ * @return 0 on success
+ */
+static int expandRegular(FSM_t fsm)
+ /*@modifies fileSystem, fsm @*/
+{
+ const char * fmd5sum;
+ const struct stat * st = &fsm->sb;
+ int left = st->st_size;
+ int rc = 0;
+
+ rc = fsmStage(fsm, FSM_WOPEN);
+ if (rc)
+ goto exit;
+
+ /* XXX md5sum's will break on repackaging that includes modified files. */
+ fmd5sum = fsm->fmd5sum;
+
+ /* XXX This doesn't support brokenEndian checks. */
+ if (st->st_size > 0 && fmd5sum)
+ fdInitMD5(fsm->wfd, 0);
+
+ while (left) {
+
+ fsm->wrlen = (left > fsm->wrsize ? fsm->wrsize : left);
+ rc = fsmStage(fsm, FSM_DREAD);
+ if (rc)
+ goto exit;
+
+ rc = fsmStage(fsm, FSM_WRITE);
+ if (rc)
+ goto exit;
+
+ left -= fsm->wrnb;
+
+ /* don't call this with fileSize == fileComplete */
+ if (!rc && left)
+ (void) fsmStage(fsm, FSM_NOTIFY);
+ }
+
+ if (st->st_size > 0 && fmd5sum) {
+ const char * md5sum = NULL;
+
+ Fflush(fsm->wfd);
+ fdFiniMD5(fsm->wfd, (void **)&md5sum, NULL, 1);
+
+ if (md5sum == NULL) {
+ rc = CPIOERR_MD5SUM_MISMATCH;
+ } else {
+ if (strcmp(md5sum, fmd5sum))
+ rc = CPIOERR_MD5SUM_MISMATCH;
+ md5sum = _free(md5sum);
+ }
+ }
+
+exit:
+ (void) fsmStage(fsm, FSM_WCLOSE);
+ return rc;
+}
+
+/** \ingroup payload
+ * Write next item to payload stream.
+ * @param fsm file state machine data
+ * @param writeData should data be written?
+ * @return 0 on success
+ */
+static int writeFile(FSM_t fsm, int writeData)
+ /*@modifies fsm @*/
+{
+ const char * path = fsm->path;
+ const char * opath = fsm->opath;
+ struct stat * st = &fsm->sb;
+ struct stat * ost = &fsm->osb;
+ size_t pos = fdGetCpioPos(fsm->cfd);
+ int left;
+ int rc;
+
+ st->st_size = (writeData ? ost->st_size : 0);
+ if (S_ISDIR(st->st_mode)) {
+ st->st_size = 0;
+ } else if (S_ISLNK(st->st_mode)) {
+ /*
+ * While linux puts the size of a symlink in the st_size field,
+ * I don't think that's a specified standard.
+ */
+ /* XXX NUL terminated result in fsm->rdbuf, len in fsm->rdnb. */
+ rc = fsmStage(fsm, FSM_READLINK);
+ if (rc) goto exit;
+ st->st_size = fsm->rdnb;
+ }
+
+ if (fsm->mapFlags & CPIO_MAP_PATH)
+ fsm->path = fsm->archivePath;
+ rc = fsmStage(fsm, FSM_HWRITE);
+ fsm->path = path;
+ if (rc) goto exit;
+
+ if (writeData && S_ISREG(st->st_mode)) {
+#if HAVE_MMAP
+ char * rdbuf = NULL;
+ void * mapped = (void *)-1;
+ size_t nmapped;
+#endif
+
+ rc = fsmStage(fsm, FSM_ROPEN);
+ if (rc) goto exit;
+
+ /* XXX unbuffered mmap generates *lots* of fdio debugging */
+#if HAVE_MMAP
+ nmapped = 0;
+ mapped = mmap(NULL, st->st_size, PROT_READ, MAP_SHARED, Fileno(fsm->rfd), 0);
+ if (mapped != (void *)-1) {
+ rdbuf = fsm->rdbuf;
+ fsm->rdbuf = (char *) mapped;
+ fsm->rdlen = nmapped = st->st_size;
+ }
+#endif
+
+ left = st->st_size;
+
+ while (left) {
+#if HAVE_MMAP
+ if (mapped != (void *)-1) {
+ fsm->rdnb = nmapped;
+ } else
+#endif
+ {
+ fsm->rdlen = (left > fsm->rdsize ? fsm->rdsize : left),
+ rc = fsmStage(fsm, FSM_READ);
+ if (rc) goto exit;
+ }
+
+ /* XXX DWRITE uses rdnb for I/O length. */
+ rc = fsmStage(fsm, FSM_DWRITE);
+ if (rc) goto exit;
+
+ left -= fsm->wrnb;
+ }
+
+#if HAVE_MMAP
+ if (mapped != (void *)-1) {
+ /*@-noeffect@*/ munmap(mapped, nmapped) /*@=noeffect@*/;
+ fsm->rdbuf = rdbuf;
+ }
+#endif
+
+ } else if (writeData && S_ISLNK(st->st_mode)) {
+ /* XXX DWRITE uses rdnb for I/O length. */
+ rc = fsmStage(fsm, FSM_DWRITE);
+ if (rc) goto exit;
+ }
+
+ rc = fsmStage(fsm, FSM_PAD);
+ if (rc) goto exit;
+
+ { const rpmTransactionSet ts = fsmGetTs(fsm);
+ TFI_t fi = fsmGetFi(fsm);
+ if (ts && fi && ts->notify) {
+ size_t size = (fdGetCpioPos(fsm->cfd) - pos);
+ (void)ts->notify(fi->h, RPMCALLBACK_INST_PROGRESS, size, size,
+ (fi->ap ? fi->ap->key : NULL), ts->notifyData);
+ }
+ }
+
+ rc = 0;
+
+exit:
+ if (fsm->rfd)
+ (void) fsmStage(fsm, FSM_RCLOSE);
+ fsm->opath = opath;
+ fsm->path = path;
+ return rc;
+}
+
+/** \ingroup payload
+ * Write set of linked files to payload stream.
+ * @param fsm file state machine data
+ * @return 0 on success
+ */
+static int writeLinkedFile(FSM_t fsm)
+ /*@modifies fsm @*/
+{
+ const char * path = fsm->path;
+ const char * nsuffix = fsm->nsuffix;
+ int iterIndex = fsm->ix;
+ int ec = 0;
+ int rc;
+ int i;
+
+ fsm->path = NULL;
+ fsm->nsuffix = NULL;
+ fsm->ix = -1;
+
+ for (i = fsm->li->nlink - 1; i >= 0; i--) {
+ if (fsm->li->filex[i] < 0) continue;
+
+ fsm->ix = fsm->li->filex[i];
+ rc = fsmStage(fsm, FSM_MAP);
+
+ /* Write data after last link. */
+ rc = writeFile(fsm, (i == 0));
+ if (rc && fsm->failedFile && *fsm->failedFile == NULL) {
+ ec = rc;
+ *fsm->failedFile = xstrdup(fsm->path);
+ }
+
+ fsm->path = _free(fsm->path);
+ fsm->li->filex[i] = -1;
+ }
+
+ fsm->ix = iterIndex;
+ fsm->nsuffix = nsuffix;
+ fsm->path = path;
+ return ec;
+}
+
+/** \ingroup payload
+ * @param fsm file state machine data
+ */
+static int fsmMakeLinks(FSM_t fsm)
+{
+ const char * path = fsm->path;
+ const char * opath = fsm->opath;
+ const char * nsuffix = fsm->nsuffix;
+ int iterIndex = fsm->ix;
+ int ec = 0;
+ int rc;
+ int i;
+
+ fsm->path = NULL;
+ fsm->opath = NULL;
+ fsm->nsuffix = NULL;
+ fsm->ix = -1;
+
+ fsm->ix = fsm->li->filex[fsm->li->createdPath];
+ rc = fsmStage(fsm, FSM_MAP);
+ fsm->opath = fsm->path;
+ fsm->path = NULL;
+ for (i = 0; i < fsm->li->nlink; i++) {
+ if (fsm->li->filex[i] < 0) continue;
+ if (i == fsm->li->createdPath) continue;
+
+ fsm->ix = fsm->li->filex[i];
+ rc = fsmStage(fsm, FSM_MAP);
+ rc = fsmStage(fsm, FSM_VERIFY);
+ if (!rc) continue;
+ if (rc != CPIOERR_LSTAT_FAILED) break;
+
+ /* XXX link(fsm->opath, fsm->path) */
+ rc = fsmStage(fsm, FSM_LINK);
+ if (rc && fsm->failedFile && *fsm->failedFile == NULL) {
+ ec = rc;
+ *fsm->failedFile = xstrdup(fsm->path);
+ }
+
+ fsm->li->linksLeft--;
+ }
+ fsm->opath = _free(fsm->opath);
+
+ fsm->ix = iterIndex;
+ fsm->nsuffix = nsuffix;
+ fsm->path = path;
+ fsm->opath = opath;
+ return ec;
+}
+
+/** \ingroup payload
+ * @param fsm file state machine data
+ */
+static int fsmCommitLinks(FSM_t fsm)
+{
+ const char * path = fsm->path;
+ const char * nsuffix = fsm->nsuffix;
+ int iterIndex = fsm->ix;
+ struct stat * st = &fsm->sb;
+ int rc = 0;
+ int i;
+
+ fsm->path = NULL;
+ fsm->nsuffix = NULL;
+ fsm->ix = -1;
+
+ for (fsm->li = fsm->links; fsm->li; fsm->li = fsm->li->next) {
+ if (fsm->li->inode == st->st_ino && fsm->li->dev == st->st_dev)
+ break;
+ }
+
+ for (i = 0; i < fsm->li->nlink; i++) {
+ if (fsm->li->filex[i] < 0) continue;
+ fsm->ix = fsm->li->filex[i];
+ rc = fsmStage(fsm, FSM_MAP);
+ rc = fsmStage(fsm, FSM_COMMIT);
+ fsm->path = _free(fsm->path);
+ fsm->li->filex[i] = -1;
+ }
+
+ fsm->ix = iterIndex;
+ fsm->nsuffix = nsuffix;
+ fsm->path = path;
+ return rc;
+}
+
+int fsmStage(FSM_t fsm, fileStage stage)
+{
+#ifdef UNUSED
+ fileStage prevStage = fsm->stage;
+ const char * const prev = fileStageString(prevStage);
+#endif
+ static int modulo = 4;
+ const char * const cur = fileStageString(stage);
+ struct stat * st = &fsm->sb;
+ struct stat * ost = &fsm->osb;
+ int saveerrno = errno;
+ int rc = fsm->rc;
+ int left;
+ int i;
+
+ if (stage & FSM_DEAD) {
+ /* do nothing */
+ } else if (stage & FSM_INTERNAL) {
+ if (_fsm_debug && !(stage & FSM_SYSCALL))
+ rpmMessage(RPMMESS_DEBUG, " %8s %06o%3d (%4d,%4d)%10d %s %s\n",
+ cur,
+ st->st_mode, st->st_nlink, st->st_uid, st->st_gid, st->st_size,
+ (fsm->path ? fsm->path : ""),
+ ((fsm->action != FA_UNKNOWN && fsm->action != FA_CREATE)
+ ? fileActionString(fsm->action) : ""));
+ } else {
+ fsm->stage = stage;
+ if (_fsm_debug || !(stage & FSM_VERBOSE))
+ rpmMessage(RPMMESS_DEBUG, "%-8s %06o%3d (%4d,%4d)%10d %s %s\n",
+ cur,
+ st->st_mode, st->st_nlink, st->st_uid, st->st_gid, st->st_size,
+ (fsm->path ? fsm->path + fsm->astriplen : ""),
+ ((fsm->action != FA_UNKNOWN && fsm->action != FA_CREATE)
+ ? fileActionString(fsm->action) : ""));
+ }
+
+ switch (stage) {
+ case FSM_UNKNOWN:
+ break;
+ case FSM_PKGINSTALL:
+ while (1) {
+ /* Clean fsm, free'ing memory. Read next archive header. */
+ rc = fsmStage(fsm, FSM_INIT);
+
+ /* Exit on end-of-payload. */
+ if (rc == CPIOERR_HDR_TRAILER) {
+ rc = 0;
+ break;
+ }
+
+ /* Exit on error. */
+ if (rc) {
+ fsm->postpone = 1;
+ (void) fsmStage(fsm, FSM_UNDO);
+ break;
+ }
+
+ /* Extract file from archive. */
+ rc = fsmStage(fsm, FSM_PROCESS);
+ if (rc) {
+ (void) fsmStage(fsm, FSM_UNDO);
+ break;
+ }
+
+ /* Notify on success. */
+ (void) fsmStage(fsm, FSM_NOTIFY);
+
+ if (fsmStage(fsm, FSM_FINI))
+ break;
+ }
+ break;
+ case FSM_PKGERASE:
+ case FSM_PKGCOMMIT:
+ while (1) {
+ /* Clean fsm, free'ing memory. */
+ rc = fsmStage(fsm, FSM_INIT);
+
+ /* Exit on end-of-payload. */
+ if (rc == CPIOERR_HDR_TRAILER) {
+ rc = 0;
+ break;
+ }
+
+ /* Rename/erase next item. */
+ if (fsmStage(fsm, FSM_FINI))
+ break;
+ }
+ break;
+ case FSM_PKGBUILD:
+ while (1) {
+
+ rc = fsmStage(fsm, FSM_INIT);
+
+ /* Exit on end-of-payload. */
+ if (rc == CPIOERR_HDR_TRAILER) {
+ rc = 0;
+ break;
+ }
+
+ /* Exit on error. */
+ if (rc) {
+ fsm->postpone = 1;
+ (void) fsmStage(fsm, FSM_UNDO);
+ break;
+ }
+
+ /* Copy file into archive. */
+ rc = fsmStage(fsm, FSM_PROCESS);
+ if (rc) {
+ (void) fsmStage(fsm, FSM_UNDO);
+ break;
+ }
+
+ if (fsmStage(fsm, FSM_FINI))
+ break;
+ }
+
+ if (!rc)
+ rc = fsmStage(fsm, FSM_TRAILER);
+ break;
+ case FSM_CREATE:
+ { rpmTransactionSet ts = fsmGetTs(fsm);
+#define _tsmask (RPMTRANS_FLAG_PKGCOMMIT | RPMTRANS_FLAG_COMMIT)
+ fsm->commit = ((ts && (ts->transFlags & _tsmask) &&
+ fsm->goal != FSM_PKGCOMMIT) ? 0 : 1);
+#undef _tsmask
+ }
+ fsm->path = _free(fsm->path);
+ fsm->opath = _free(fsm->opath);
+ fsm->dnlx = _free(fsm->dnlx);
+
+ fsm->ldn = _free(fsm->ldn);
+ fsm->ldnalloc = fsm->ldnlen = 0;
+
+ fsm->rdsize = fsm->wrsize = 0;
+ fsm->rdbuf = fsm->rdb = _free(fsm->rdb);
+ fsm->wrbuf = fsm->wrb = _free(fsm->wrb);
+ if (fsm->goal == FSM_PKGINSTALL || fsm->goal == FSM_PKGBUILD) {
+ fsm->rdsize = 8 * BUFSIZ;
+ fsm->rdbuf = fsm->rdb = xmalloc(fsm->rdsize);
+ fsm->wrsize = 8 * BUFSIZ;
+ fsm->wrbuf = fsm->wrb = xmalloc(fsm->wrsize);
+ }
+
+ fsm->mkdirsdone = 0;
+ fsm->ix = -1;
+ fsm->links = NULL;
+ fsm->li = NULL;
+ errno = 0; /* XXX get rid of EBADF */
+
+ /* Detect and create directories not explicitly in package. */
+ if (fsm->goal == FSM_PKGINSTALL) {
+ rc = fsmStage(fsm, FSM_MKDIRS);
+ if (!rc) fsm->mkdirsdone = 1;
+ }
+
+ break;
+ case FSM_INIT:
+ fsm->path = _free(fsm->path);
+ fsm->postpone = 0;
+ fsm->diskchecked = fsm->exists = 0;
+ fsm->subdir = NULL;
+ fsm->suffix = (fsm->sufbuf[0] != '\0' ? fsm->sufbuf : NULL);
+ fsm->action = FA_UNKNOWN;
+ fsm->osuffix = NULL;
+ fsm->nsuffix = NULL;
+
+ if (fsm->goal == FSM_PKGINSTALL) {
+ /* Read next header from payload, checking for end-of-payload. */
+ rc = fsmStage(fsm, FSM_NEXT);
+ }
+ if (rc) break;
+
+ /* Identify mapping index. */
+ fsm->ix = ((fsm->goal == FSM_PKGINSTALL)
+ ? mapFind(fsm->iter, fsm->path) : mapNextIterator(fsm->iter));
+
+ /* On non-install, detect end-of-loop. */
+ if (fsm->goal != FSM_PKGINSTALL && fsm->ix < 0) {
+ rc = CPIOERR_HDR_TRAILER;
+ break;
+ }
+
+ /* On non-install, mode must be known so that dirs don't get suffix. */
+ if (fsm->goal != FSM_PKGINSTALL) {
+ TFI_t fi = fsmGetFi(fsm);
+ st->st_mode = fi->fmodes[fsm->ix];
+ }
+
+ /* Generate file path. */
+ rc = fsmStage(fsm, FSM_MAP);
+ if (rc) break;
+
+ /* Perform lstat/stat for disk file. */
+ rc = fsmStage(fsm, (!(fsm->mapFlags & CPIO_FOLLOW_SYMLINKS)
+ ? FSM_LSTAT : FSM_STAT));
+ if (rc == CPIOERR_LSTAT_FAILED && errno == ENOENT) {
+ errno = saveerrno;
+ rc = 0;
+ fsm->exists = 0;
+ } else if (rc == 0) {
+ fsm->exists = 1;
+ }
+ fsm->diskchecked = 1;
+ if (rc) break;
+
+ /* On non-install, the disk file stat is what's remapped. */
+ if (fsm->goal != FSM_PKGINSTALL)
+ *st = *ost; /* structure assignment */
+
+ /* Remap file perms, owner, and group. */
+ rc = fsmMapAttrs(fsm);
+ if (rc) break;
+
+ fsm->postpone = XFA_SKIPPING(fsm->action);
+ if (fsm->goal == FSM_PKGINSTALL || fsm->goal == FSM_PKGBUILD) {
+ if (!S_ISDIR(st->st_mode) && st->st_nlink > 1)
+ fsm->postpone = saveHardLink(fsm);
+ }
+ break;
+ case FSM_PRE:
+ break;
+ case FSM_MAP:
+ rc = fsmMapPath(fsm);
+ break;
+ case FSM_MKDIRS:
+ { const char * path = fsm->path;
+ mode_t st_mode = st->st_mode;
+ void * dnli = dnlInitIterator(fsm, 0);
+ char * dn = fsm->rdbuf;
+ int dc = dnlCount(dnli);
+
+ fsm->path = NULL;
+ dn[0] = '\0';
+ fsm->dnlx = (dc ? xcalloc(dc, sizeof(*fsm->dnlx)) : NULL);
+ while ((fsm->path = dnlNextIterator(dnli)) != NULL) {
+ int dnlen = strlen(fsm->path);
+ char * te;
+
+ dc = dnlIndex(dnli);
+ if (dc < 0) continue;
+ fsm->dnlx[dc] = dnlen;
+ if (dnlen <= 1)
+ continue;
+ if (dnlen <= fsm->ldnlen && !strcmp(fsm->path, fsm->ldn))
+ continue;
+
+ /* Copy to avoid const on fsm->path. */
+ (void) stpcpy(dn, fsm->path);
+ fsm->path = dn;
+
+ /* Initial mode for created dirs is 0700 */
+ st->st_mode &= ~07777; /* XXX abuse st->st_mode */
+ st->st_mode |= 00700;
+
+ /* Assume '/' directory, otherwise "mkdir -p" */
+ for (i = 1, te = dn + 1; *te; te++, i++) {
+ if (*te != '/') continue;
+
+ *te = '\0';
+
+ /* Already validated? */
+ if (i < fsm->ldnlen &&
+ (fsm->ldn[i] == '/' || fsm->ldn[i] == '\0') &&
+ !strncmp(fsm->path, fsm->ldn, i))
+ {
+ *te = '/';
+ /* Move pre-existing path marker forward. */
+ fsm->dnlx[dc] = (te - dn);
+ continue;
+ }
+
+ /* Validate next component of path. */
+ rc = fsmStage(fsm, FSM_LSTAT);
+ *te = '/';
+
+ /* Directory already exists? */
+ if (rc == 0 && S_ISDIR(ost->st_mode)) {
+ /* Move pre-existing path marker forward. */
+ fsm->dnlx[dc] = (te - dn);
+ } else if (rc == CPIOERR_LSTAT_FAILED) {
+ TFI_t fi = fsmGetFi(fsm);
+ mode_t st_mode = st->st_mode;
+ *te = '\0';
+ st->st_mode = S_IFDIR | (fi->dperms & 07777);
+ rc = fsmStage(fsm, FSM_MKDIR);
+ if (!rc)
+ rpmMessage(RPMMESS_WARNING,
+ _("%s directory created with perms %04o.\n"),
+ fsm->path, (st->st_mode & 07777));
+ *te = '/';
+ st->st_mode = st_mode;
+ }
+ if (rc) break;
+ }
+ if (rc) break;
+
+ /* Save last validated path. */
+ if (fsm->ldnalloc < (dnlen + 1)) {
+ fsm->ldnalloc = dnlen + 100;
+ fsm->ldn = xrealloc(fsm->ldn, fsm->ldnalloc);
+ }
+ strcpy(fsm->ldn, fsm->path);
+ fsm->ldnlen = dnlen;
+ }
+ dnli = dnlFreeIterator(dnli);
+ fsm->path = path;
+ st->st_mode = st_mode; /* XXX restore st->st_mode */
+ }
+ break;
+ case FSM_RMDIRS:
+ if (fsm->dnlx) {
+ const char * path = fsm->path;
+ void * dnli = dnlInitIterator(fsm, 1);
+ char * dn = fsm->rdbuf;
+ int dc = dnlCount(dnli);
+
+ fsm->path = NULL;
+ dn[0] = '\0';
+ while ((fsm->path = dnlNextIterator(dnli)) != NULL) {
+ int dnlen = strlen(fsm->path);
+ char * te;
+
+ dc = dnlIndex(dnli);
+ if (fsm->dnlx[dc] < 1 || fsm->dnlx[dc] >= dnlen)
+ continue;
+
+ /* Copy to avoid const on fsm->path. */
+ te = stpcpy(dn, fsm->path) - 1;
+ fsm->path = dn;
+
+ /* Remove generated directories. */
+ do {
+ if (*te == '/') {
+ *te = '\0';
+ rc = fsmStage(fsm, FSM_RMDIR);
+ *te = '/';
+ }
+ if (rc) break;
+ te--;
+ } while ((te - dn) > fsm->dnlx[dc]);
+ }
+ dnli = dnlFreeIterator(dnli);
+ fsm->path = path;
+ }
+ break;
+ case FSM_PROCESS:
+ if (fsm->postpone) {
+ if (fsm->goal == FSM_PKGINSTALL)
+ rc = fsmStage(fsm, FSM_EAT);
+ break;
+ }
+
+ if (fsm->goal == FSM_PKGBUILD) {
+ if (!S_ISDIR(st->st_mode) && st->st_nlink > 1) {
+ struct hardLink * li, * prev;
+ rc = writeLinkedFile(fsm);
+ if (rc) break; /* W2DO? */
+
+ for (li = fsm->links, prev = NULL; li; prev = li, li = li->next)
+ if (li == fsm->li) break;
+
+ if (prev == NULL)
+ fsm->links = fsm->li->next;
+ else
+ prev->next = fsm->li->next;
+ fsm->li->next = NULL;
+ fsm->li = freeHardLink(fsm->li);
+ } else {
+ rc = writeFile(fsm, 1);
+ }
+ break;
+ }
+
+ if (fsm->goal != FSM_PKGINSTALL)
+ break;
+
+ if (S_ISREG(st->st_mode)) {
+ const char * path = fsm->path;
+ if (fsm->osuffix)
+ fsm->path = fsmFsPath(fsm, st, NULL, NULL);
+ rc = fsmStage(fsm, FSM_VERIFY);
+
+ if (rc == 0 && fsm->osuffix) {
+ const char * opath = fsm->opath;
+ fsm->opath = fsm->path;
+ fsm->path = fsmFsPath(fsm, st, NULL, fsm->osuffix);
+ rc = fsmStage(fsm, FSM_RENAME);
+ if (!rc)
+ rpmMessage(RPMMESS_WARNING,
+ _("%s saved as %s\n"), fsm->opath, fsm->path);
+ fsm->path = _free(fsm->path);
+ fsm->opath = opath;
+ }
+
+ fsm->path = path;
+ if (rc != CPIOERR_LSTAT_FAILED) return rc;
+ rc = expandRegular(fsm);
+ } else if (S_ISDIR(st->st_mode)) {
+ mode_t st_mode = st->st_mode;
+ rc = fsmStage(fsm, FSM_VERIFY);
+ if (rc == CPIOERR_LSTAT_FAILED) {
+ st->st_mode &= ~07777; /* XXX abuse st->st_mode */
+ st->st_mode |= 00700;
+ rc = fsmStage(fsm, FSM_MKDIR);
+ st->st_mode = st_mode; /* XXX restore st->st_mode */
+ }
+ } else if (S_ISLNK(st->st_mode)) {
+ const char * opath = fsm->opath;
+
+ if ((st->st_size + 1) > fsm->rdsize) {
+ rc = CPIOERR_HDR_SIZE;
+ break;
+ }
+
+ fsm->wrlen = st->st_size;
+ rc = fsmStage(fsm, FSM_DREAD);
+ if (!rc && fsm->rdnb != fsm->wrlen)
+ rc = CPIOERR_READ_FAILED;
+ if (rc) break;
+
+ fsm->wrbuf[st->st_size] = '\0';
+ /* XXX symlink(fsm->opath, fsm->path) */
+ fsm->opath = fsm->wrbuf; /* XXX abuse fsm->path */
+ rc = fsmStage(fsm, FSM_VERIFY);
+ if (rc == CPIOERR_LSTAT_FAILED)
+ rc = fsmStage(fsm, FSM_SYMLINK);
+ fsm->opath = opath; /* XXX restore fsm->path */
+ } else if (S_ISFIFO(st->st_mode)) {
+ mode_t st_mode = st->st_mode;
+ /* This mimics cpio S_ISSOCK() behavior but probably isnt' right */
+ rc = fsmStage(fsm, FSM_VERIFY);
+ if (rc == CPIOERR_LSTAT_FAILED) {
+ st->st_mode = 0000; /* XXX abuse st->st_mode */
+ rc = fsmStage(fsm, FSM_MKFIFO);
+ st->st_mode = st_mode; /* XXX restore st->st_mode */
+ }
+ } else if (S_ISCHR(st->st_mode) ||
+ S_ISBLK(st->st_mode) ||
+ S_ISSOCK(st->st_mode))
+ {
+ rc = fsmStage(fsm, FSM_VERIFY);
+ if (rc == CPIOERR_LSTAT_FAILED)
+ rc = fsmStage(fsm, FSM_MKNOD);
+ } else {
+ rc = CPIOERR_UNKNOWN_FILETYPE;
+ }
+ if (!S_ISDIR(st->st_mode) && st->st_nlink > 1) {
+ fsm->li->createdPath = fsm->li->linkIndex;
+ rc = fsmMakeLinks(fsm);
+ }
+ break;
+ case FSM_POST:
+ break;
+ case FSM_MKLINKS:
+ break;
+ case FSM_NOTIFY: /* XXX move from fsm to psm -> tsm */
+ if (fsm->goal == FSM_PKGINSTALL || fsm->goal == FSM_PKGBUILD) {
+ rpmTransactionSet ts = fsmGetTs(fsm);
+ TFI_t fi = fsmGetFi(fsm);
+ if (ts && ts->notify && fi)
+ (void)ts->notify(fi->h, RPMCALLBACK_INST_PROGRESS,
+ fdGetCpioPos(fsm->cfd), fi->archiveSize,
+ (fi->ap ? fi->ap->key : NULL), ts->notifyData);
+ }
+ break;
+ case FSM_UNDO:
+ if (fsm->postpone)
+ break;
+ if (fsm->goal == FSM_PKGINSTALL) {
+ (void) fsmStage(fsm,
+ (S_ISDIR(st->st_mode) ? FSM_RMDIR : FSM_UNLINK));
+
+#ifdef NOTYET /* XXX remove only dirs just created, not all. */
+ if (fsm->dnlx)
+ (void) fsmStage(fsm, FSM_RMDIRS);
+#endif
+ errno = saveerrno;
+ }
+ if (fsm->failedFile && *fsm->failedFile == NULL)
+ *fsm->failedFile = xstrdup(fsm->path);
+ break;
+ case FSM_FINI:
+ if (!fsm->postpone && fsm->commit) {
+ if (fsm->goal == FSM_PKGINSTALL)
+ rc = ((!S_ISDIR(st->st_mode) && st->st_nlink > 1)
+ ? fsmCommitLinks(fsm) : fsmStage(fsm, FSM_COMMIT));
+ if (fsm->goal == FSM_PKGCOMMIT)
+ rc = fsmStage(fsm, FSM_COMMIT);
+ if (fsm->goal == FSM_PKGERASE)
+ rc = fsmStage(fsm, FSM_COMMIT);
+ }
+ fsm->path = _free(fsm->path);
+ fsm->opath = _free(fsm->opath);
+ memset(st, 0, sizeof(*st));
+ memset(ost, 0, sizeof(*ost));
+ break;
+ case FSM_COMMIT:
+ /* Rename pre-existing modified or unmanaged file. */
+ if (fsm->diskchecked && fsm->exists && fsm->osuffix) {
+ const char * opath = fsm->opath;
+ const char * path = fsm->path;
+ fsm->opath = fsmFsPath(fsm, st, NULL, NULL);
+ fsm->path = fsmFsPath(fsm, st, NULL, fsm->osuffix);
+ rc = fsmStage(fsm, FSM_RENAME);
+ if (!rc) {
+ rpmMessage(RPMMESS_WARNING, _("%s saved as %s\n"),
+ fsm->opath, fsm->path);
+ }
+ fsm->path = _free(fsm->path);
+ fsm->path = path;
+ fsm->opath = _free(fsm->opath);
+ fsm->opath = opath;
+ }
+
+ /* Remove erased files. */
+ if (fsm->goal == FSM_PKGERASE) {
+ if (fsm->action == FA_ERASE) {
+ TFI_t fi = fsmGetFi(fsm);
+ if (S_ISDIR(st->st_mode)) {
+ rc = fsmStage(fsm, FSM_RMDIR);
+ if (!rc) break;
+ switch (errno) {
+ case ENOENT: /* XXX rmdir("/") linux 2.2.x kernel hack */
+ case ENOTEMPTY:
+ /* XXX make sure that build side permits %missingok on directories. */
+ if (fsm->fflags & RPMFILE_MISSINGOK)
+ break;
+
+ /* XXX common error message. */
+ rpmError(RPMERR_RMDIR,
+ _("%s rmdir of %s failed: Directory not empty\n"),
+ fiTypeString(fi), fsm->path);
+ break;
+ default:
+ rpmError(RPMERR_RMDIR,
+ _("%s rmdir of %s failed: %s\n"),
+ fiTypeString(fi), fsm->path, strerror(errno));
+ break;
+ }
+ } else {
+ rc = fsmStage(fsm, FSM_UNLINK);
+ if (!rc) break;
+ if (!(errno == ENOENT && (fsm->fflags & RPMFILE_MISSINGOK)))
+ rpmError(RPMERR_UNLINK,
+ _("%s unlink of %s failed: %s\n"),
+ fiTypeString(fi), fsm->path, strerror(errno));
+ }
+ }
+ break;
+ }
+
+ if (!S_ISSOCK(st->st_mode)) { /* XXX /dev/log et al are skipped */
+ /* Rename temporary to final file name. */
+ if (!S_ISDIR(st->st_mode) &&
+ (fsm->subdir || fsm->suffix || fsm->nsuffix))
+ {
+ fsm->opath = fsm->path;
+ fsm->path = fsmFsPath(fsm, st, NULL, fsm->nsuffix);
+ rc = fsmStage(fsm, FSM_RENAME);
+ if (!rc && fsm->nsuffix) {
+ const char * opath = fsmFsPath(fsm, st, NULL, NULL);
+ rpmMessage(RPMMESS_WARNING, _("%s created as %s\n"),
+ opath, fsm->path);
+ opath = _free(opath);
+ }
+ fsm->opath = _free(fsm->opath);
+ }
+ if (S_ISLNK(st->st_mode)) {
+ if (!rc && !getuid())
+ rc = fsmStage(fsm, FSM_LCHOWN);
+ } else {
+ if (!rc && !getuid())
+ rc = fsmStage(fsm, FSM_CHOWN);
+ if (!rc)
+ rc = fsmStage(fsm, FSM_CHMOD);
+ if (!rc) {
+ time_t st_mtime = st->st_mtime;
+ TFI_t fi = fsmGetFi(fsm);
+ if (fi->fmtimes)
+ st->st_mtime = fi->fmtimes[fsm->ix];
+ rc = fsmStage(fsm, FSM_UTIME);
+ st->st_mtime = st_mtime;
+ }
+ }
+ }
+
+ /* Notify on success. */
+ if (!rc) rc = fsmStage(fsm, FSM_NOTIFY);
+ break;
+ case FSM_DESTROY:
+ fsm->path = _free(fsm->path);
+
+ /* Create any remaining links (if no error), and clean up. */
+ while ((fsm->li = fsm->links) != NULL) {
+ fsm->links = fsm->li->next;
+ fsm->li->next = NULL;
+ if (fsm->goal == FSM_PKGINSTALL && fsm->commit && fsm->li->linksLeft)
+ {
+ for (i = 0 ; i < fsm->li->linksLeft; i++) {
+ if (fsm->li->filex[i] < 0) continue;
+ rc = CPIOERR_MISSING_HARDLINK;
+ if (fsm->failedFile && *fsm->failedFile == NULL) {
+ fsm->ix = fsm->li->filex[i];
+ if (!fsmStage(fsm, FSM_MAP)) {
+ *fsm->failedFile = fsm->path;
+ fsm->path = NULL;
+ }
+ }
+ break;
+ }
+ }
+ if (fsm->goal == FSM_PKGBUILD) {
+ rc = CPIOERR_MISSING_HARDLINK;
+ }
+ fsm->li = freeHardLink(fsm->li);
+ }
+ fsm->ldn = _free(fsm->ldn);
+ fsm->ldnalloc = fsm->ldnlen = 0;
+ fsm->rdbuf = fsm->rdb = _free(fsm->rdb);
+ fsm->wrbuf = fsm->wrb = _free(fsm->wrb);
+ break;
+ case FSM_VERIFY:
+ if (fsm->diskchecked && !fsm->exists) {
+ rc = CPIOERR_LSTAT_FAILED;
+ break;
+ }
+ if (S_ISREG(st->st_mode)) {
+ char * path = alloca(strlen(fsm->path) + sizeof("-RPMDELETE"));
+ (void) stpcpy( stpcpy(path, fsm->path), "-RPMDELETE");
+ /*
+ * XXX HP-UX (and other os'es) don't permit unlink on busy
+ * XXX files.
+ */
+ fsm->opath = fsm->path;
+ fsm->path = path;
+ rc = fsmStage(fsm, FSM_RENAME);
+ if (!rc)
+ (void) fsmStage(fsm, FSM_UNLINK);
+ else
+ rc = CPIOERR_UNLINK_FAILED;
+ fsm->path = fsm->opath;
+ fsm->opath = NULL;
+ return (rc ? rc : CPIOERR_LSTAT_FAILED); /* XXX HACK */
+ /*@notreached@*/ break;
+ } else if (S_ISDIR(st->st_mode)) {
+ if (S_ISDIR(ost->st_mode)) return 0;
+ if (S_ISLNK(ost->st_mode)) {
+ rc = fsmStage(fsm, FSM_STAT);
+ if (rc == CPIOERR_STAT_FAILED && errno == ENOENT) rc = 0;
+ if (rc) break;
+ errno = saveerrno;
+ if (S_ISDIR(ost->st_mode)) return 0;
+ }
+ } else if (S_ISLNK(st->st_mode)) {
+ if (S_ISLNK(ost->st_mode)) {
+ /* XXX NUL terminated result in fsm->rdbuf, len in fsm->rdnb. */
+ rc = fsmStage(fsm, FSM_READLINK);
+ errno = saveerrno;
+ if (rc) break;
+ if (!strcmp(fsm->opath, fsm->rdbuf)) return 0;
+ }
+ } else if (S_ISFIFO(st->st_mode)) {
+ if (S_ISFIFO(ost->st_mode)) return 0;
+ } else if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
+ if ((S_ISCHR(ost->st_mode) || S_ISBLK(ost->st_mode)) &&
+ (ost->st_rdev == st->st_rdev)) return 0;
+ } else if (S_ISSOCK(st->st_mode)) {
+ if (S_ISSOCK(ost->st_mode)) return 0;
+ }
+ /* XXX shouldn't do this with commit/undo. */
+ rc = 0;
+ if (fsm->stage == FSM_PROCESS) rc = fsmStage(fsm, FSM_UNLINK);
+ if (rc == 0) rc = CPIOERR_LSTAT_FAILED;
+ return (rc ? rc : CPIOERR_LSTAT_FAILED); /* XXX HACK */
+ /*@notreached@*/ break;
+
+ case FSM_UNLINK:
+ rc = Unlink(fsm->path);
+ if (_fsm_debug && (stage & FSM_SYSCALL))
+ rpmMessage(RPMMESS_DEBUG, " %8s (%s) %s\n", cur,
+ fsm->path, (rc < 0 ? strerror(errno) : ""));
+ if (rc < 0) rc = CPIOERR_UNLINK_FAILED;
+ break;
+ case FSM_RENAME:
+ rc = Rename(fsm->opath, fsm->path);
+ if (_fsm_debug && (stage & FSM_SYSCALL))
+ rpmMessage(RPMMESS_DEBUG, " %8s (%s, %s) %s\n", cur,
+ fsm->opath, fsm->path, (rc < 0 ? strerror(errno) : ""));
+ if (rc < 0) rc = CPIOERR_RENAME_FAILED;
+ break;
+ case FSM_MKDIR:
+ rc = Mkdir(fsm->path, (st->st_mode & 07777));
+ if (_fsm_debug && (stage & FSM_SYSCALL))
+ rpmMessage(RPMMESS_DEBUG, " %8s (%s, 0%04o) %s\n", cur,
+ fsm->path, (st->st_mode & 07777),
+ (rc < 0 ? strerror(errno) : ""));
+ if (rc < 0) rc = CPIOERR_MKDIR_FAILED;
+ break;
+ case FSM_RMDIR:
+ rc = Rmdir(fsm->path);
+ if (_fsm_debug && (stage & FSM_SYSCALL))
+ rpmMessage(RPMMESS_DEBUG, " %8s (%s) %s\n", cur,
+ fsm->path, (rc < 0 ? strerror(errno) : ""));
+ if (rc < 0) rc = CPIOERR_RMDIR_FAILED;
+ break;
+ case FSM_CHOWN:
+ rc = chown(fsm->path, st->st_uid, st->st_gid);
+ if (_fsm_debug && (stage & FSM_SYSCALL))
+ rpmMessage(RPMMESS_DEBUG, " %8s (%s, %d, %d) %s\n", cur,
+ fsm->path, st->st_uid, st->st_gid,
+ (rc < 0 ? strerror(errno) : ""));
+ if (rc < 0) rc = CPIOERR_CHOWN_FAILED;
+ break;
+ case FSM_LCHOWN:
+#if ! CHOWN_FOLLOWS_SYMLINK
+ rc = lchown(fsm->path, st->st_uid, st->st_gid);
+ if (_fsm_debug && (stage & FSM_SYSCALL))
+ rpmMessage(RPMMESS_DEBUG, " %8s (%s, %d, %d) %s\n", cur,
+ fsm->path, st->st_uid, st->st_gid,
+ (rc < 0 ? strerror(errno) : ""));
+ if (rc < 0) rc = CPIOERR_CHOWN_FAILED;
+#endif
+ break;
+ case FSM_CHMOD:
+ rc = chmod(fsm->path, (st->st_mode & 07777));
+ if (_fsm_debug && (stage & FSM_SYSCALL))
+ rpmMessage(RPMMESS_DEBUG, " %8s (%s, 0%04o) %s\n", cur,
+ fsm->path, (st->st_mode & 07777),
+ (rc < 0 ? strerror(errno) : ""));
+ if (rc < 0) rc = CPIOERR_CHMOD_FAILED;
+ break;
+ case FSM_UTIME:
+ { struct utimbuf stamp;
+ stamp.actime = st->st_mtime;
+ stamp.modtime = st->st_mtime;
+ rc = utime(fsm->path, &stamp);
+ if (_fsm_debug && (stage & FSM_SYSCALL))
+ rpmMessage(RPMMESS_DEBUG, " %8s (%s, 0x%x) %s\n", cur,
+ fsm->path, (unsigned)st->st_mtime,
+ (rc < 0 ? strerror(errno) : ""));
+ if (rc < 0) rc = CPIOERR_UTIME_FAILED;
+ }
+ break;
+ case FSM_SYMLINK:
+ rc = symlink(fsm->opath, fsm->path);
+ if (_fsm_debug && (stage & FSM_SYSCALL))
+ rpmMessage(RPMMESS_DEBUG, " %8s (%s, %s) %s\n", cur,
+ fsm->opath, fsm->path, (rc < 0 ? strerror(errno) : ""));
+ if (rc < 0) rc = CPIOERR_SYMLINK_FAILED;
+ break;
+ case FSM_LINK:
+ rc = Link(fsm->opath, fsm->path);
+ if (_fsm_debug && (stage & FSM_SYSCALL))
+ rpmMessage(RPMMESS_DEBUG, " %8s (%s, %s) %s\n", cur,
+ fsm->opath, fsm->path, (rc < 0 ? strerror(errno) : ""));
+ if (rc < 0) rc = CPIOERR_LINK_FAILED;
+ break;
+ case FSM_MKFIFO:
+ rc = mkfifo(fsm->path, (st->st_mode & 07777));
+ if (_fsm_debug && (stage & FSM_SYSCALL))
+ rpmMessage(RPMMESS_DEBUG, " %8s (%s, 0%04o) %s\n", cur,
+ fsm->path, (st->st_mode & 07777),
+ (rc < 0 ? strerror(errno) : ""));
+ if (rc < 0) rc = CPIOERR_MKFIFO_FAILED;
+ break;
+ case FSM_MKNOD:
+ /*@-unrecog@*/
+ rc = mknod(fsm->path, (st->st_mode & ~07777), st->st_rdev);
+ if (_fsm_debug && (stage & FSM_SYSCALL))
+ rpmMessage(RPMMESS_DEBUG, " %8s (%s, 0%o, 0x%x) %s\n", cur,
+ fsm->path, (st->st_mode & ~07777), (unsigned)st->st_rdev,
+ (rc < 0 ? strerror(errno) : ""));
+ if (rc < 0) rc = CPIOERR_MKNOD_FAILED;
+ /*@=unrecog@*/
+ break;
+ case FSM_LSTAT:
+ rc = Lstat(fsm->path, ost);
+ if (_fsm_debug && (stage & FSM_SYSCALL) && rc && errno != ENOENT)
+ rpmMessage(RPMMESS_DEBUG, " %8s (%s, ost) %s\n", cur,
+ fsm->path, (rc < 0 ? strerror(errno) : ""));
+ if (rc < 0) rc = CPIOERR_LSTAT_FAILED;
+ break;
+ case FSM_STAT:
+ rc = Stat(fsm->path, ost);
+ if (_fsm_debug && (stage & FSM_SYSCALL) && rc && errno != ENOENT)
+ rpmMessage(RPMMESS_DEBUG, " %8s (%s, ost) %s\n", cur,
+ fsm->path, (rc < 0 ? strerror(errno) : ""));
+ if (rc < 0) rc = CPIOERR_STAT_FAILED;
+ break;
+ case FSM_READLINK:
+ /* XXX NUL terminated result in fsm->rdbuf, len in fsm->rdnb. */
+ rc = Readlink(fsm->path, fsm->rdbuf, fsm->rdsize - 1);
+ if (_fsm_debug && (stage & FSM_SYSCALL))
+ rpmMessage(RPMMESS_DEBUG, " %8s (%s, rdbuf, %d) %s\n", cur,
+ fsm->path, fsm->rdlen, (rc < 0 ? strerror(errno) : ""));
+ if (rc < 0) rc = CPIOERR_READLINK_FAILED;
+ else {
+ fsm->rdnb = rc;
+ fsm->rdbuf[fsm->rdnb] = '\0';
+ rc = 0;
+ }
+ break;
+ case FSM_CHROOT:
+ break;
+
+ case FSM_NEXT:
+ rc = fsmStage(fsm, FSM_HREAD);
+ if (rc) break;
+ if (!strcmp(fsm->path, CPIO_TRAILER)) { /* Detect end-of-payload. */
+ fsm->path = _free(fsm->path);
+ rc = CPIOERR_HDR_TRAILER;
+ }
+ if (!rc)
+ rc = fsmStage(fsm, FSM_POS);
+ break;
+ case FSM_EAT:
+ for (left = st->st_size; left > 0; left -= fsm->rdnb) {
+ fsm->wrlen = (left > fsm->wrsize ? fsm->wrsize : left);
+ rc = fsmStage(fsm, FSM_DREAD);
+ if (rc) break;
+ }
+ break;
+ case FSM_POS:
+ left = (modulo - (fdGetCpioPos(fsm->cfd) % modulo)) % modulo;
+ if (left) {
+ fsm->wrlen = left;
+ (void) fsmStage(fsm, FSM_DREAD);
+ }
+ break;
+ case FSM_PAD:
+ left = (modulo - (fdGetCpioPos(fsm->cfd) % modulo)) % modulo;
+ if (left) {
+ memset(fsm->rdbuf, 0, left);
+ /* XXX DWRITE uses rdnb for I/O length. */
+ fsm->rdnb = left;
+ (void) fsmStage(fsm, FSM_DWRITE);
+ }
+ break;
+ case FSM_TRAILER:
+ rc = cpioTrailerWrite(fsm);
+ break;
+ case FSM_HREAD:
+ rc = fsmStage(fsm, FSM_POS);
+ if (!rc)
+ rc = cpioHeaderRead(fsm, st); /* Read next payload header. */
+ break;
+ case FSM_HWRITE:
+ rc = cpioHeaderWrite(fsm, st); /* Write next payload header. */
+ break;
+ case FSM_DREAD:
+ fsm->rdnb = Fread(fsm->wrbuf, sizeof(*fsm->wrbuf), fsm->wrlen, fsm->cfd);
+ if (_fsm_debug && (stage & FSM_SYSCALL))
+ rpmMessage(RPMMESS_DEBUG, " %8s (%s, %d, cfd)\trdnb %d\n",
+ cur, (fsm->wrbuf == fsm->wrb ? "wrbuf" : "mmap"),
+ fsm->wrlen, fsm->rdnb);
+if (fsm->rdnb != fsm->wrlen) fprintf(stderr, "*** short read, had %d, got %d\n", (int)fsm->rdnb, (int)fsm->wrlen);
+#ifdef NOTYET
+ if (Ferror(fsm->rfd))
+ rc = CPIOERR_READ_FAILED;
+#endif
+ if (fsm->rdnb > 0)
+ fdSetCpioPos(fsm->cfd, fdGetCpioPos(fsm->cfd) + fsm->rdnb);
+ break;
+ case FSM_DWRITE:
+ fsm->wrnb = Fwrite(fsm->rdbuf, sizeof(*fsm->rdbuf), fsm->rdnb, fsm->cfd);
+ if (_fsm_debug && (stage & FSM_SYSCALL))
+ rpmMessage(RPMMESS_DEBUG, " %8s (%s, %d, cfd)\twrnb %d\n",
+ cur, (fsm->rdbuf == fsm->rdb ? "rdbuf" : "mmap"),
+ fsm->rdnb, fsm->wrnb);
+if (fsm->rdnb != fsm->wrnb) fprintf(stderr, "*** short write, had %d, got %d\n", (int)fsm->rdnb, (int)fsm->wrnb);
+#ifdef NOTYET
+ if (Ferror(fsm->wfd))
+ rc = CPIOERR_WRITE_FAILED;
+#endif
+ if (fsm->wrnb > 0)
+ fdSetCpioPos(fsm->cfd, fdGetCpioPos(fsm->cfd) + fsm->wrnb);
+ break;
+
+ case FSM_ROPEN:
+ fsm->rfd = Fopen(fsm->path, "r.ufdio");
+ if (fsm->rfd == NULL || Ferror(fsm->rfd)) {
+ if (fsm->rfd) (void) fsmStage(fsm, FSM_RCLOSE);
+ fsm->rfd = NULL;
+ rc = CPIOERR_OPEN_FAILED;
+ break;
+ }
+ if (_fsm_debug && (stage & FSM_SYSCALL))
+ rpmMessage(RPMMESS_DEBUG, " %8s (%s, \"r\") rfd %p rdbuf %p\n", cur,
+ fsm->path, fsm->rfd, fsm->rdbuf);
+ break;
+ case FSM_READ:
+ fsm->rdnb = Fread(fsm->rdbuf, sizeof(*fsm->rdbuf), fsm->rdlen, fsm->rfd);
+ if (_fsm_debug && (stage & FSM_SYSCALL))
+ rpmMessage(RPMMESS_DEBUG, " %8s (rdbuf, %d, rfd)\trdnb %d\n",
+ cur, fsm->rdlen, fsm->rdnb);
+if (fsm->rdnb != fsm->rdlen) fprintf(stderr, "*** short read, had %d, got %d\n", (int)fsm->rdnb, (int)fsm->rdlen);
+#ifdef NOTYET
+ if (Ferror(fsm->rfd))
+ rc = CPIOERR_READ_FAILED;
+#endif
+ break;
+ case FSM_RCLOSE:
+ if (fsm->rfd) {
+ if (_fsm_debug && (stage & FSM_SYSCALL))
+ rpmMessage(RPMMESS_DEBUG, " %8s (%p)\n", cur, fsm->rfd);
+ (void) Fclose(fsm->rfd);
+ errno = saveerrno;
+ }
+ fsm->rfd = NULL;
+ break;
+ case FSM_WOPEN:
+ fsm->wfd = Fopen(fsm->path, "w.ufdio");
+ if (fsm->wfd == NULL || Ferror(fsm->wfd)) {
+ if (fsm->wfd) (void) fsmStage(fsm, FSM_WCLOSE);
+ fsm->wfd = NULL;
+ rc = CPIOERR_OPEN_FAILED;
+ }
+ if (_fsm_debug && (stage & FSM_SYSCALL))
+ rpmMessage(RPMMESS_DEBUG, " %8s (%s, \"w\") wfd %p wrbuf %p\n", cur,
+ fsm->path, fsm->wfd, fsm->wrbuf);
+ break;
+ case FSM_WRITE:
+ fsm->wrnb = Fwrite(fsm->wrbuf, sizeof(*fsm->wrbuf), fsm->rdnb, fsm->wfd);
+ if (_fsm_debug && (stage & FSM_SYSCALL))
+ rpmMessage(RPMMESS_DEBUG, " %8s (wrbuf, %d, wfd)\twrnb %d\n",
+ cur, fsm->rdnb, fsm->wrnb);
+if (fsm->rdnb != fsm->wrnb) fprintf(stderr, "*** short write: had %d, got %d\n", (int)fsm->rdnb, (int)fsm->wrnb);
+#ifdef NOTYET
+ if (Ferror(fsm->wfd))
+ rc = CPIOERR_WRITE_FAILED;
+#endif
+ break;
+ case FSM_WCLOSE:
+ if (fsm->wfd) {
+ if (_fsm_debug && (stage & FSM_SYSCALL))
+ rpmMessage(RPMMESS_DEBUG, " %8s (%p)\n", cur, fsm->wfd);
+ (void) Fclose(fsm->wfd);
+ errno = saveerrno;
+ }
+ fsm->wfd = NULL;
+ break;
+
+ default:
+ break;
+ }
+
+ if (!(stage & FSM_INTERNAL)) {
+ fsm->rc = (rc == CPIOERR_HDR_TRAILER ? 0 : rc);
+ }
+ return rc;
+}
+
+/*@observer@*/ const char *const fileStageString(fileStage a) {
+ switch(a) {
+ case FSM_UNKNOWN: return "unknown";
+
+ case FSM_PKGINSTALL:return "pkginstall";
+ case FSM_PKGERASE: return "pkgerase";
+ case FSM_PKGBUILD: return "pkgbuild";
+ case FSM_PKGCOMMIT: return "pkgcommit";
+ case FSM_PKGUNDO: return "pkgundo";
+
+ case FSM_CREATE: return "create";
+ case FSM_INIT: return "init";
+ case FSM_MAP: return "map";
+ case FSM_MKDIRS: return "mkdirs";
+ case FSM_RMDIRS: return "rmdirs";
+ case FSM_PRE: return "pre";
+ case FSM_PROCESS: return "process";
+ case FSM_POST: return "post";
+ case FSM_MKLINKS: return "mklinks";
+ case FSM_NOTIFY: return "notify";
+ case FSM_UNDO: return "undo";
+ case FSM_FINI: return "fini";
+ case FSM_COMMIT: return "commit";
+ case FSM_DESTROY: return "destroy";
+ case FSM_VERIFY: return "verify";
+
+ case FSM_UNLINK: return "Unlink";
+ case FSM_RENAME: return "Rename";
+ case FSM_MKDIR: return "Mkdir";
+ case FSM_RMDIR: return "rmdir";
+ case FSM_CHOWN: return "chown";
+ case FSM_LCHOWN: return "lchown";
+ case FSM_CHMOD: return "chmod";
+ case FSM_UTIME: return "utime";
+ case FSM_SYMLINK: return "symlink";
+ case FSM_LINK: return "Link";
+ case FSM_MKFIFO: return "mkfifo";
+ case FSM_MKNOD: return "mknod";
+ case FSM_LSTAT: return "Lstat";
+ case FSM_STAT: return "Stat";
+ case FSM_READLINK: return "Readlink";
+ case FSM_CHROOT: return "chroot";
+
+ case FSM_NEXT: return "next";
+ case FSM_EAT: return "eat";
+ case FSM_POS: return "pos";
+ case FSM_PAD: return "pad";
+ case FSM_TRAILER: return "trailer";
+ case FSM_HREAD: return "hread";
+ case FSM_HWRITE: return "hwrite";
+ case FSM_DREAD: return "Fread";
+ case FSM_DWRITE: return "Fwrite";
+
+ case FSM_ROPEN: return "Fopen";
+ case FSM_READ: return "Fread";
+ case FSM_RCLOSE: return "Fclose";
+ case FSM_WOPEN: return "Fopen";
+ case FSM_WRITE: return "Fwrite";
+ case FSM_WCLOSE: return "Fclose";
+
+ default: return "???";
+ }
+ /*@noteached@*/
+}
--- /dev/null
+#ifndef H_FSM
+#define H_FSM
+
+/** \file lib/fsm.h
+ */
+
+#include <rpmlib.h>
+#include "cpio.h"
+
+/**
+ */
+#define FSM_VERBOSE 0x8000
+#define FSM_INTERNAL 0x4000
+#define FSM_SYSCALL 0x2000
+#define FSM_DEAD 0x1000
+#define _fv(_a) ((_a) | FSM_VERBOSE)
+#define _fi(_a) ((_a) | FSM_INTERNAL)
+#define _fs(_a) ((_a) | (FSM_INTERNAL | FSM_SYSCALL))
+#define _fd(_a) ((_a) | (FSM_INTERNAL | FSM_DEAD))
+typedef enum fileStage_e {
+ FSM_UNKNOWN = 0,
+ FSM_INIT = _fd(1),
+ FSM_PRE = _fd(2),
+ FSM_PROCESS = _fv(3),
+ FSM_POST = _fd(4),
+ FSM_UNDO = 5,
+ FSM_FINI = 6,
+
+ FSM_PKGINSTALL = _fd(7),
+ FSM_PKGERASE = _fd(8),
+ FSM_PKGBUILD = _fd(9),
+ FSM_PKGCOMMIT = _fd(10),
+ FSM_PKGUNDO = _fd(11),
+
+ FSM_CREATE = _fd(17),
+ FSM_MAP = _fd(18),
+ FSM_MKDIRS = _fi(19),
+ FSM_RMDIRS = _fi(20),
+ FSM_MKLINKS = _fi(21),
+ FSM_NOTIFY = _fd(22),
+ FSM_DESTROY = _fd(23),
+ FSM_VERIFY = _fd(24),
+ FSM_COMMIT = _fd(25),
+
+ FSM_UNLINK = _fs(33),
+ FSM_RENAME = _fs(34),
+ FSM_MKDIR = _fs(35),
+ FSM_RMDIR = _fs(36),
+ FSM_CHOWN = _fs(37),
+ FSM_LCHOWN = _fs(38),
+ FSM_CHMOD = _fs(39),
+ FSM_UTIME = _fs(40),
+ FSM_SYMLINK = _fs(41),
+ FSM_LINK = _fs(42),
+ FSM_MKFIFO = _fs(43),
+ FSM_MKNOD = _fs(44),
+ FSM_LSTAT = _fs(45),
+ FSM_STAT = _fs(46),
+ FSM_READLINK= _fs(47),
+ FSM_CHROOT = _fs(48),
+
+ FSM_NEXT = _fd(65),
+ FSM_EAT = _fd(66),
+ FSM_POS = _fd(67),
+ FSM_PAD = _fd(68),
+ FSM_TRAILER = _fd(69),
+ FSM_HREAD = _fd(70),
+ FSM_HWRITE = _fd(71),
+ FSM_DREAD = _fs(72),
+ FSM_DWRITE = _fs(73),
+
+ FSM_ROPEN = _fs(129),
+ FSM_READ = _fs(130),
+ FSM_RCLOSE = _fs(131),
+ FSM_WOPEN = _fs(132),
+ FSM_WRITE = _fs(133),
+ FSM_WCLOSE = _fs(134),
+} fileStage;
+#undef _fv
+#undef _fi
+#undef _fs
+#undef _fd
+
+/** \ingroup payload
+ * Keeps track of the set of all hard links to a file in an archive.
+ */
+struct hardLink {
+/*@owned@*/ struct hardLink * next;
+/*@owned@*/ const char ** nsuffix;
+/*@owned@*/ int * filex;
+ dev_t dev;
+ ino_t inode;
+ int nlink;
+ int linksLeft;
+ int linkIndex;
+ int createdPath;
+};
+
+/** \ingroup payload
+ * Iterator across package file info, forward on install, backward on erase.
+ */
+struct fsmIterator_s {
+/*@kept@*/ rpmTransactionSet ts; /*!< transaction set. */
+/*@kept@*/ TFI_t fi; /*!< transaction element file info. */
+ int isave; /*!< last returned iterator index. */
+ int i; /*!< iterator index. */
+};
+
+/** \ingroup payload
+ * File name and stat information.
+ */
+struct fsm_s {
+/*@owned@*/ const char * path; /*!< Current file name. */
+/*@owned@*/ const char * opath; /*!< Original file name. */
+ FD_t cfd; /*!< Payload file handle. */
+ FD_t rfd; /*!< read: File handle. */
+/*@dependent@*/ char * rdbuf; /*!< read: Buffer. */
+/*@owned@*/ char * rdb; /*!< read: Buffer allocated. */
+ size_t rdsize; /*!< read: Buffer allocated size. */
+ size_t rdlen; /*!< read: Number of bytes requested. */
+ size_t rdnb; /*!< read: Number of bytes returned. */
+ FD_t wfd; /*!< write: File handle. */
+/*@dependent@*/ char * wrbuf; /*!< write: Buffer. */
+/*@owned@*/ char * wrb; /*!< write: Buffer allocated. */
+ size_t wrsize; /*!< write: Buffer allocated size. */
+ size_t wrlen; /*!< write: Number of bytes requested. */
+ size_t wrnb; /*!< write: Number of bytes returned. */
+/*@only@*/ FSMI_t iter; /*!< File iterator. */
+ int ix; /*!< Current file iterator index. */
+/*@only@*/ struct hardLink * links; /*!< Pending hard linked file(s). */
+/*@only@*/ struct hardLink * li; /*!< Current hard linked file(s). */
+/*@kept@*/ unsigned int * archiveSize; /*!< Pointer to archive size. */
+/*@kept@*/ const char ** failedFile; /*!< First file name that failed. */
+/*@shared@*/ const char * subdir; /*!< Current file sub-directory. */
+ char subbuf[64]; /* XXX eliminate */
+/*@observer@*/ const char * osuffix; /*!< Old, preserved, file suffix. */
+/*@observer@*/ const char * nsuffix; /*!< New, created, file suffix. */
+/*@shared@*/ const char * suffix; /*!< Current file suffix. */
+ char sufbuf[64]; /* XXX eliminate */
+/*@only@*/ short * dnlx; /*!< Last dirpath verified indexes. */
+/*@only@*/ char * ldn; /*!< Last dirpath verified. */
+ int ldnlen; /*!< Last dirpath current length. */
+ int ldnalloc; /*!< Last dirpath allocated length. */
+ int postpone; /*!< Skip remaining stages? */
+ int diskchecked; /*!< Has stat(2) been performed? */
+ int exists; /*!< Does current file exist on disk? */
+ int mkdirsdone; /*!< Have "orphan" dirs been created? */
+ int astriplen; /*!< Length of buildroot prefix. */
+ int rc; /*!< External file stage return code. */
+ int commit; /*!< Commit synchronously? */
+ cpioMapFlags mapFlags; /*!< Bit(s) to control mapping. */
+/*@shared@*/ const char * archivePath; /*!< Path to store in cpio archive. */
+/*@shared@*/ const char * dirName; /*!< File directory name. */
+/*@shared@*/ const char * baseName; /*!< File base name. */
+/*@shared@*/ const char * fmd5sum; /*!< File MD5 sum (NULL disables). */
+ unsigned fflags; /*!< File flags. */
+ fileAction action; /*!< File disposition. */
+ fileStage goal; /*!< Package state machine goal. */
+ fileStage stage; /*!< External file stage. */
+ struct stat sb; /*!< Current file stat(2) info. */
+ struct stat osb; /*!< Original file stat(2) info. */
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Return formatted string representation of file stages.
+ * @param a file stage
+ * @return formatted string
+ */
+/*@observer@*/ const char *const fileStageString(fileStage a);
+
+/**
+ * Create file state machine instance.
+ * @return file state machine data
+ */
+/*@only@*/ /*@null@*/ FSM_t newFSM(void);
+
+/**
+ * Destroy file state machine instance.
+ * @param fsm file state machine data
+ * @return always NULL
+ */
+/*@null@*/ FSM_t freeFSM(/*@only@*/ /*@null@*/ FSM_t fsm);
+
+/**
+ * Load external data into file state machine.
+ * @param fsm file state machine data
+ * @param goal
+ * @param ts transaction set
+ * @param fi transaction element file info
+ * @param archiveSize pointer to archive size
+ * @param failedFile pointer to first file name that failed.
+ * @return 0 on success
+ */
+int fsmSetup(FSM_t fsm, fileStage goal,
+ /*@kept@*/ const rpmTransactionSet ts,
+ /*@kept@*/ const TFI_t fi,
+ FD_t cfd,
+ /*@out@*/ unsigned int * archiveSize,
+ /*@out@*/ const char ** failedFile)
+ /*@modifies fsm, *archiveSize, *failedFile @*/;
+
+/**
+ * Clean file state machine.
+ * @param fsm file state machine data
+ * @return 0 on success
+ */
+int fsmTeardown(FSM_t fsm)
+ /*@modifies fsm @*/;
+
+/**
+ * Retrieve transaction set from file state machine iterator.
+ * @param fsm file state machine data
+ * @return transaction set
+ */
+/*@kept@*/ rpmTransactionSet fsmGetTs(const FSM_t fsm) /*@*/;
+
+/**
+ * Retrieve transaction element file info from file state machine iterator.
+ * @param fsm file state machine data
+ * @return transaction element file info
+ */
+/*@kept@*/ TFI_t fsmGetFi(const FSM_t fsm) /*@*/;
+
+/**
+ * Map next file path and action.
+ * @param fsm file state machine data
+ */
+int fsmMapPath(FSM_t fsm)
+ /*@modifies fsm @*/;
+
+/**
+ * Map file stat(2) info.
+ * @param fsm file state machine data
+ */
+int fsmMapAttrs(FSM_t fsm)
+ /*@modifies fsm @*/;
+
+/**
+ * File state machine driver.
+ * @param fsm file state machine data
+ * @param stage next stage
+ * @return 0 on success
+ */
+int fsmStage(FSM_t fsm, fileStage stage)
+ /*@modifies fsm @*/;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* H_FSM */
/** \ingroup rpmtrans payload
- * \file lib/install.c
+ * \file lib/psm.c
*/
#include "system.h"
#include <rpmmacro.h>
#include <rpmurl.h>
-#include "rollback.h"
+#include "psm.h"
#include "misc.h"
#include "debug.h"
-/*@access Header @*/ /* XXX compared with NULL */
-/*@access rpmTransactionSet @*/ /* XXX compared with NULL */
+/*@access Header @*/ /* compared with NULL */
+/*@access rpmTransactionSet @*/ /* compared with NULL */
+/*@access TFI_t @*/ /* compared with NULL */
+
+extern int _fsm_debug;
+
+/**
+ * Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
+ * @param this memory to free
+ * @retval NULL always
+ */
+static /*@null@*/ void * _free(/*@only@*/ /*@null@*/ const void * this) {
+ if (this) free((void *)this);
+ return NULL;
+}
+
+void loadFi(Header h, TFI_t fi)
+{
+ HGE_t hge;
+ HFD_t hfd;
+ uint_32 * uip;
+ int len;
+ int rc;
+ int i;
+
+ if (fi->fsm == NULL)
+ fi->fsm = newFSM();
+
+ /* XXX avoid gcc noise on pointer (4th arg) cast(s) */
+ hge = (fi->type == TR_ADDED)
+ ? (HGE_t) headerGetEntryMinMemory : (HGE_t) headerGetEntry;
+ fi->hge = hge;
+
+ fi->hfd = hfd = headerFreeData;
+
+ if (h && fi->h == NULL) fi->h = headerLink(h);
+
+ /* Duplicate name-version-release so that headers can be free'd. */
+ hge(fi->h, RPMTAG_NAME, NULL, (void **) &fi->name, NULL);
+ fi->name = xstrdup(fi->name);
+ hge(fi->h, RPMTAG_VERSION, NULL, (void **) &fi->version, NULL);
+ fi->version = xstrdup(fi->version);
+ hge(fi->h, RPMTAG_RELEASE, NULL, (void **) &fi->release, NULL);
+ fi->release = xstrdup(fi->release);
+
+ /* -1 means not found */
+ rc = hge(fi->h, RPMTAG_EPOCH, NULL, (void **) &uip, NULL);
+ fi->epoch = (rc ? *uip : -1);
+ /* 0 means unknown */
+ rc = hge(fi->h, RPMTAG_ARCHIVESIZE, NULL, (void **) &uip, NULL);
+ fi->archiveSize = (rc ? *uip : 0);
+
+ if (!hge(fi->h, RPMTAG_BASENAMES, NULL, (void **) &fi->bnl, &fi->fc)) {
+ fi->dc = 0;
+ fi->fc = 0;
+ return;
+ }
+
+ hge(fi->h, RPMTAG_DIRINDEXES, NULL, (void **) &fi->dil, NULL);
+ hge(fi->h, RPMTAG_DIRNAMES, NULL, (void **) &fi->dnl, &fi->dc);
+ hge(fi->h, RPMTAG_FILEMODES, NULL, (void **) &fi->fmodes, NULL);
+ hge(fi->h, RPMTAG_FILEFLAGS, NULL, (void **) &fi->fflags, NULL);
+ hge(fi->h, RPMTAG_FILESIZES, NULL, (void **) &fi->fsizes, NULL);
+ hge(fi->h, RPMTAG_FILESTATES, NULL, (void **) &fi->fstates, NULL);
+
+ fi->action = FA_UNKNOWN;
+ fi->flags = 0;
+
+ /* actions is initialized earlier for added packages */
+ if (fi->actions == NULL)
+ fi->actions = xcalloc(fi->fc, sizeof(*fi->actions));
+
+ switch (fi->type) {
+ case TR_ADDED:
+ fi->mapflags = CPIO_MAP_PATH | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
+ hge(fi->h, RPMTAG_FILEMD5S, NULL, (void **) &fi->fmd5s, NULL);
+ hge(fi->h, RPMTAG_FILELINKTOS, NULL, (void **) &fi->flinks, NULL);
+ hge(fi->h, RPMTAG_FILELANGS, NULL, (void **) &fi->flangs, NULL);
+ hge(fi->h, RPMTAG_FILEMTIMES, NULL, (void **) &fi->fmtimes, NULL);
+
+ /* 0 makes for noops */
+ fi->replacedSizes = xcalloc(fi->fc, sizeof(*fi->replacedSizes));
+
+ break;
+ case TR_REMOVED:
+ fi->mapflags = CPIO_MAP_PATH;
+ hge(fi->h, RPMTAG_FILEMD5S, NULL, (void **) &fi->fmd5s, NULL);
+ hge(fi->h, RPMTAG_FILELINKTOS, NULL, (void **) &fi->flinks, NULL);
+ fi->fsizes = memcpy(xmalloc(fi->fc * sizeof(*fi->fsizes)),
+ fi->fsizes, fi->fc * sizeof(*fi->fsizes));
+ fi->fflags = memcpy(xmalloc(fi->fc * sizeof(*fi->fflags)),
+ fi->fflags, fi->fc * sizeof(*fi->fflags));
+ fi->fmodes = memcpy(xmalloc(fi->fc * sizeof(*fi->fmodes)),
+ fi->fmodes, fi->fc * sizeof(*fi->fmodes));
+ /* XXX there's a tedious segfault here for some version(s) of rpm */
+ if (fi->fstates)
+ fi->fstates = memcpy(xmalloc(fi->fc * sizeof(*fi->fstates)),
+ fi->fstates, fi->fc * sizeof(*fi->fstates));
+ else
+ fi->fstates = xcalloc(1, fi->fc * sizeof(*fi->fstates));
+ fi->dil = memcpy(xmalloc(fi->fc * sizeof(*fi->dil)),
+ fi->dil, fi->fc * sizeof(*fi->dil));
+ headerFree(fi->h);
+ fi->h = NULL;
+ break;
+ }
+
+ fi->dnlmax = -1;
+ for (i = 0; i < fi->dc; i++) {
+ if ((len = strlen(fi->dnl[i])) > fi->dnlmax)
+ fi->dnlmax = len;
+ }
+
+ fi->bnlmax = -1;
+ for (i = 0; i < fi->fc; i++) {
+ if ((len = strlen(fi->bnl[i])) > fi->bnlmax)
+ fi->bnlmax = len;
+ }
+
+ fi->dperms = 0755;
+ fi->fperms = 0644;
+
+ return;
+}
+
+void freeFi(TFI_t fi)
+{
+ HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
+
+ fi->name = _free(fi->name);
+ fi->version = _free(fi->version);
+ fi->release = _free(fi->release);
+ fi->actions = _free(fi->actions);
+ fi->replacedSizes = _free(fi->replacedSizes);
+ fi->replaced = _free(fi->replaced);
+
+ fi->bnl = hfd(fi->bnl, -1);
+ fi->dnl = hfd(fi->dnl, -1);
+ fi->obnl = hfd(fi->obnl, -1);
+ fi->odnl = hfd(fi->odnl, -1);
+ fi->flinks = hfd(fi->flinks, -1);
+ fi->fmd5s = hfd(fi->fmd5s, -1);
+ fi->fuser = hfd(fi->fuser, -1);
+ fi->fgroup = hfd(fi->fgroup, -1);
+ fi->flangs = hfd(fi->flangs, -1);
+
+ fi->apath = _free(fi->apath);
+ fi->fuids = _free(fi->fuids);
+ fi->fgids = _free(fi->fgids);
+ fi->fmapflags = _free(fi->fmapflags);
+
+ fi->fsm = freeFSM(fi->fsm);
+
+ switch (fi->type) {
+ case TR_ADDED:
+ break;
+ case TR_REMOVED:
+ fi->fsizes = hfd(fi->fsizes, -1);
+ fi->fflags = hfd(fi->fflags, -1);
+ fi->fmodes = hfd(fi->fmodes, -1);
+ fi->fstates = hfd(fi->fstates, -1);
+ fi->dil = hfd(fi->dil, -1);
+ break;
+ }
+ if (fi->h) {
+ headerFree(fi->h); fi->h = NULL;
+ }
+}
+
+/*@observer@*/ const char *const fiTypeString(TFI_t fi) {
+ switch(fi->type) {
+ case TR_ADDED: return " install";
+ case TR_REMOVED: return " erase";
+ default: return "???";
+ }
+ /*@noteached@*/
+}
+
+/*@obserever@*/ const char *const fileActionString(fileAction a)
+{
+ switch (a) {
+ case FA_UNKNOWN: return "unknown";
+ case FA_CREATE: return "create";
+ case FA_BACKUP: return "backup";
+ case FA_SAVE: return "save";
+ case FA_SKIP: return "skip";
+ case FA_ALTNAME: return "altname";
+ case FA_ERASE: return "erase";
+ case FA_SKIPNSTATE: return "skipnstate";
+ case FA_SKIPNETSHARED: return "skipnetshared";
+ case FA_SKIPMULTILIB: return "skipmultilib";
+ default: return "???";
+ }
+ /*@notreached@*/
+}
+
+#ifdef DYING
+/**
+ */
+struct pkgIterator {
+/*@dependent@*/ /*@kept@*/ TFI_t fi;
+ int i;
+};
+
+/**
+ */
+static /*@null@*/ void * pkgFreeIterator(/*@only@*/ /*@null@*/ void * this) {
+ return _free(this);
+}
+
+/**
+ */
+static /*@only@*/ void * pkgInitIterator(/*@kept@*/ rpmTransactionSet ts,
+ /*@kept@*/ TFI_t fi)
+{
+ struct pkgIterator * pi = NULL;
+ if (ts && fi) {
+ pi = xcalloc(sizeof(*pi), 1);
+ pi->fi = fi;
+ switch (fi->type) {
+ case TR_ADDED: pi->i = 0; break;
+ case TR_REMOVED: pi->i = fi->fc; break;
+ }
+ }
+ return pi;
+}
+
+/**
+ */
+static int pkgNextIterator(/*@null@*/ void * this) {
+ struct pkgIterator * pi = this;
+ int i = -1;
+
+ if (pi) {
+ TFI_t fi = pi->fi;
+ switch (fi->type) {
+ case TR_ADDED:
+ if (pi->i < fi->fc)
+ i = pi->i++;
+ break;
+ case TR_REMOVED:
+ if (pi->i >= 0)
+ i = --pi->i;
+ break;
+ }
+ }
+ return i;
+}
+
+int pkgActions(const rpmTransactionSet ts, TFI_t fi, fileStage a)
+{
+ int rc = 0;
+
+ if (fi->actions) {
+ void * pi = pkgInitIterator(ts, fi);
+ int i;
+ while ((i = pkgNextIterator(pi)) != -1) {
+ if (pkgAction(ts, fi, i, a))
+ rc++;
+ }
+ pi = pkgFreeIterator(pi);
+ }
+ return rc;
+}
+#endif
+
/**
* Macros to be defined from per-header tag values.
headerFree(oldH);
return ec;
}
+
+int removeBinaryPackage(const rpmTransactionSet ts, TFI_t fi)
+{
+/*@observer@*/ static char * stepName = " erase";
+ Header h;
+ int chrootDone = 0;
+ const char * failedFile = NULL;
+ const void * pkgKey = NULL;
+ int rc = 0;
+
+ rpmMessage(RPMMESS_DEBUG, _("%s: %s-%s-%s has %d files, test = %d\n"),
+ stepName, fi->name, fi->version, fi->release,
+ fi->fc, (ts->transFlags & RPMTRANS_FLAG_TEST));
+
+ /*
+ * When we run scripts, we pass an argument which is the number of
+ * versions of this package that will be installed when we are finished.
+ */
+ fi->scriptArg = rpmdbCountPackages(ts->rpmdb, fi->name) - 1;
+ if (fi->scriptArg < 0)
+ return 1;
+
+ { rpmdbMatchIterator mi = NULL;
+
+ mi = rpmdbInitIterator(ts->rpmdb, RPMDBI_PACKAGES,
+ &fi->record, sizeof(fi->record));
+
+ h = rpmdbNextIterator(mi);
+ if (h == NULL) {
+ rpmdbFreeIterator(mi);
+ return 2;
+ }
+ h = headerLink(h);
+ rpmdbFreeIterator(mi);
+ }
+
+ if (ts->rootDir && !ts->chrootDone) {
+ chdir("/");
+ /*@-unrecog@*/ chroot(ts->rootDir); /*@=unrecog@*/
+ chrootDone = ts->chrootDone = 1;
+ }
+
+ if (!(ts->transFlags & RPMTRANS_FLAG_NOTRIGGERS)) {
+ /* run triggers from this package which are keyed on installed
+ packages */
+ if (runImmedTriggers(ts, RPMSENSE_TRIGGERUN, h, -1))
+ return 2;
+
+ /* run triggers which are set off by the removal of this package */
+ if (runTriggers(ts, RPMSENSE_TRIGGERUN, h, -1))
+ return 1;
+ }
+
+ rpmMessage(RPMMESS_DEBUG, _("%s: running %s script(s) (if any)\n"),
+ stepName, "pre-erase");
+
+ rc = runInstScript(ts, h, RPMTAG_PREUN, RPMTAG_PREUNPROG, fi->scriptArg,
+ (ts->transFlags & RPMTRANS_FLAG_NOSCRIPTS));
+ if (rc)
+ return 1;
+
+ if (fi->fc > 0 && !(ts->transFlags & RPMTRANS_FLAG_JUSTDB)) {
+
+ if (ts->notify)
+ (void)ts->notify(h, RPMCALLBACK_UNINST_START, fi->fc, fi->fc,
+ pkgKey, ts->notifyData);
+
+ rc = fsmSetup(fi->fsm, FSM_PKGERASE, ts, fi, NULL, NULL, &failedFile);
+ (void) fsmTeardown(fi->fsm);
+
+ if (ts->notify)
+ (void)ts->notify(h, RPMCALLBACK_UNINST_STOP, 0, fi->fc,
+ pkgKey, ts->notifyData);
+ }
+
+ rpmMessage(RPMMESS_DEBUG, _("%s: running %s script(s) (if any)\n"),
+ stepName, "post-erase");
+
+ rc = runInstScript(ts, h, RPMTAG_POSTUN, RPMTAG_POSTUNPROG,
+ fi->scriptArg, (ts->transFlags & RPMTRANS_FLAG_NOSCRIPTS));
+ /* XXX postun failures are not cause for erasure failure. */
+
+ if (!(ts->transFlags & RPMTRANS_FLAG_NOTRIGGERS)) {
+ /* Run postun triggers which are set off by this package's removal. */
+ rc = runTriggers(ts, RPMSENSE_TRIGGERPOSTUN, h, -1);
+ if (rc)
+ return 2;
+ }
+
+ if (ts->rootDir && chrootDone) {
+ /*@-unrecog@*/ chroot("."); /*@=unrecog@*/
+ chrootDone = ts->chrootDone = 0;
+ chdir(ts->currDir);
+ }
+
+ if (!(ts->transFlags & RPMTRANS_FLAG_TEST))
+ rpmdbRemove(ts->rpmdb, ts->id, fi->record);
+
+ return 0;
+}
--- /dev/null
+#ifndef H_PSM
+#define H_PSM
+
+/** \file lib/psm.h
+ */
+
+#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;
+ int secFileNumber;
+} ;
+
+/**
+ */
+struct sharedFileInfo {
+ int pkgFileNum;
+ int otherFileNum;
+ int otherPkg;
+ int isRemoved;
+};
+
+/**
+ */
+struct transactionFileInfo_s {
+ /* for all packages */
+ enum rpmTransactionType type;
+ fileAction action; /*!< File disposition default. */
+/*@owned@*/ fileAction * actions; /*!< File disposition(s) */
+/*@owned@*/ struct fingerPrint_s * fps; /*!< File fingerprint(s) */
+ HGE_t hge; /*!< Vector to headerGetEntry() */
+ HFD_t hfd; /*!< Vector to headerFreeData() */
+ Header h; /*!< Package header */
+/*@owned@*/ const char * name;
+/*@owned@*/ const char * version;
+/*@owned@*/ const char * release;
+ int_32 epoch;
+ uint_32 flags; /*!< File flag default. */
+ const uint_32 * fflags; /*!< File flag(s) (from header) */
+ const uint_32 * fsizes; /*!< File size(s) (from header) */
+ const uint_32 * fmtimes; /*!< File modification time(s) (from header) */
+/*@owned@*/ const char ** bnl; /*!< Base name(s) (from header) */
+/*@owned@*/ const char ** dnl; /*!< Directory name(s) (from header) */
+ int_32 * dil; /*!< Directory indice(s) (from header) */
+/*@owned@*/ const char ** obnl; /*!< Original base name(s) (from header) */
+/*@owned@*/ const char ** odnl; /*!< Original directory name(s) (from header) */
+ int_32 * odil; /*!< Original directory indice(s) (from header) */
+/*@owned@*/ const char ** fmd5s;/*!< File MD5 sum(s) (from header) */
+/*@owned@*/ const char ** flinks; /*!< File link(s) (from header) */
+/* XXX setuid/setgid bits are turned off if fuser/fgroup doesn't map. */
+ uint_16 * fmodes; /*!< File mode(s) (from header) */
+/*@owned@*/ char * fstates; /*!< File state(s) (from header) */
+/*@owned@*/ const char ** fuser; /*!< File owner(s) */
+/*@owned@*/ const char ** fgroup; /*!< File group(s) */
+/*@owned@*/ const char ** flangs; /*!< File lang(s) */
+ int fc; /*!< No. of files. */
+ int dc; /*!< No. of directories. */
+ int bnlmax; /*!< Length (in bytes) of longest base name. */
+ int dnlmax; /*!< Length (in bytes) of longest dir name. */
+ int astriplen;
+ int striplen;
+ int scriptArg;
+ unsigned int archiveSize;
+ mode_t dperms; /*!< Directory perms (0755) if not mapped. */
+ mode_t fperms; /*!< File perms (0644) if not mapped. */
+/*@owned@*/ const char ** apath;
+ int mapflags;
+/*@owned@*/ int * fmapflags;
+ uid_t uid;
+/*@owned@*/ /*@null@*/ uid_t * fuids; /*!< File uid(s) */
+ gid_t gid;
+/*@owned@*/ /*@null@*/ gid_t * fgids; /*!< File gid(s) */
+ int magic;
+#define TFIMAGIC 0x09697923
+/*@owned@*/ FSM_t fsm; /*!< File state machine data. */
+
+ /* these are for TR_ADDED packages */
+/*@dependent@*/ struct availablePackage * ap;
+/*@owned@*/ struct sharedFileInfo * replaced;
+/*@owned@*/ uint_32 * replacedSizes;
+ /* for TR_REMOVED packages */
+ unsigned int record;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Load data from header into transaction file element info.
+ * @param h header
+ * @param fi transaction element file info
+ */
+void loadFi(Header h, TFI_t fi)
+ /*@modifies h, fi @*/;
+
+/**
+ * Destroy transaction element file info.
+ * @param fi transaction element file info
+ */
+void freeFi(TFI_t fi)
+ /*@modifies fi @*/;
+
+/**
+ * Return formatted string representation of package disposition.
+ * @param a package dispostion
+ * @return formatted string
+ */
+/*@observer@*/ const char *const fiTypeString(TFI_t fi);
+
+/**
+ * Return formatted string representation of file disposition.
+ * @param a file dispostion
+ * @return formatted string
+ */
+/*@observer@*/ const char *const fileActionString(fileAction a);
+
+/**
+ * Install binary package (from transaction set).
+ * @param ts transaction set
+ * @param fi transaction element file info
+ * @return 0 on success, 1 on bad magic, 2 on error
+ */
+int installBinaryPackage(const rpmTransactionSet ts, TFI_t fi);
+
+/**
+ * Erase binary package (from transaction set).
+ * @param ts transaction set
+ * @param fi transaction element file info
+ * @param pkgKey package private data
+ * @return 0 on success
+ */
+int removeBinaryPackage(const rpmTransactionSet ts, TFI_t fi);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* H_ROLLBACK */
+++ /dev/null
-/** \ingroup rpmtrans payload
- * \file lib/rollback.c
- */
-
-#include "system.h"
-
-#include <rpmlib.h>
-
-#include "rollback.h"
-
-#include "debug.h"
-
-/*@access Header @*/ /* compared with NULL */
-/*@access rpmTransactionSet @*/ /* compared with NULL */
-/*@access TFI_t @*/ /* compared with NULL */
-
-static /*@null@*/ void * _free(/*@only@*/ /*@null@*/ const void * this) {
- if (this) free((void *)this);
- return NULL;
-}
-
-void loadFi(Header h, TFI_t fi)
-{
- HGE_t hge;
- HFD_t hfd;
- uint_32 * uip;
- int len;
- int rc;
- int i;
-
- if (fi->fsm == NULL)
- fi->fsm = newFSM();
-
- /* XXX avoid gcc noise on pointer (4th arg) cast(s) */
- hge = (fi->type == TR_ADDED)
- ? (HGE_t) headerGetEntryMinMemory : (HGE_t) headerGetEntry;
- fi->hge = hge;
-
- fi->hfd = hfd = headerFreeData;
-
- if (h && fi->h == NULL) fi->h = headerLink(h);
-
- /* Duplicate name-version-release so that headers can be free'd. */
- hge(fi->h, RPMTAG_NAME, NULL, (void **) &fi->name, NULL);
- fi->name = xstrdup(fi->name);
- hge(fi->h, RPMTAG_VERSION, NULL, (void **) &fi->version, NULL);
- fi->version = xstrdup(fi->version);
- hge(fi->h, RPMTAG_RELEASE, NULL, (void **) &fi->release, NULL);
- fi->release = xstrdup(fi->release);
-
- /* -1 means not found */
- rc = hge(fi->h, RPMTAG_EPOCH, NULL, (void **) &uip, NULL);
- fi->epoch = (rc ? *uip : -1);
- /* 0 means unknown */
- rc = hge(fi->h, RPMTAG_ARCHIVESIZE, NULL, (void **) &uip, NULL);
- fi->archiveSize = (rc ? *uip : 0);
-
- if (!hge(fi->h, RPMTAG_BASENAMES, NULL, (void **) &fi->bnl, &fi->fc)) {
- fi->dc = 0;
- fi->fc = 0;
- return;
- }
-
- hge(fi->h, RPMTAG_DIRINDEXES, NULL, (void **) &fi->dil, NULL);
- hge(fi->h, RPMTAG_DIRNAMES, NULL, (void **) &fi->dnl, &fi->dc);
- hge(fi->h, RPMTAG_FILEMODES, NULL, (void **) &fi->fmodes, NULL);
- hge(fi->h, RPMTAG_FILEFLAGS, NULL, (void **) &fi->fflags, NULL);
- hge(fi->h, RPMTAG_FILESIZES, NULL, (void **) &fi->fsizes, NULL);
- hge(fi->h, RPMTAG_FILESTATES, NULL, (void **) &fi->fstates, NULL);
-
- fi->action = FA_UNKNOWN;
- fi->flags = 0;
-
- /* actions is initialized earlier for added packages */
- if (fi->actions == NULL)
- fi->actions = xcalloc(fi->fc, sizeof(*fi->actions));
-
- switch (fi->type) {
- case TR_ADDED:
- fi->mapflags = CPIO_MAP_PATH | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
- hge(fi->h, RPMTAG_FILEMD5S, NULL, (void **) &fi->fmd5s, NULL);
- hge(fi->h, RPMTAG_FILELINKTOS, NULL, (void **) &fi->flinks, NULL);
- hge(fi->h, RPMTAG_FILELANGS, NULL, (void **) &fi->flangs, NULL);
- hge(fi->h, RPMTAG_FILEMTIMES, NULL, (void **) &fi->fmtimes, NULL);
-
- /* 0 makes for noops */
- fi->replacedSizes = xcalloc(fi->fc, sizeof(*fi->replacedSizes));
-
- break;
- case TR_REMOVED:
- fi->mapflags = CPIO_MAP_PATH;
- hge(fi->h, RPMTAG_FILEMD5S, NULL, (void **) &fi->fmd5s, NULL);
- hge(fi->h, RPMTAG_FILELINKTOS, NULL, (void **) &fi->flinks, NULL);
- fi->fsizes = memcpy(xmalloc(fi->fc * sizeof(*fi->fsizes)),
- fi->fsizes, fi->fc * sizeof(*fi->fsizes));
- fi->fflags = memcpy(xmalloc(fi->fc * sizeof(*fi->fflags)),
- fi->fflags, fi->fc * sizeof(*fi->fflags));
- fi->fmodes = memcpy(xmalloc(fi->fc * sizeof(*fi->fmodes)),
- fi->fmodes, fi->fc * sizeof(*fi->fmodes));
- /* XXX there's a tedious segfault here for some version(s) of rpm */
- if (fi->fstates)
- fi->fstates = memcpy(xmalloc(fi->fc * sizeof(*fi->fstates)),
- fi->fstates, fi->fc * sizeof(*fi->fstates));
- else
- fi->fstates = xcalloc(1, fi->fc * sizeof(*fi->fstates));
- fi->dil = memcpy(xmalloc(fi->fc * sizeof(*fi->dil)),
- fi->dil, fi->fc * sizeof(*fi->dil));
- headerFree(fi->h);
- fi->h = NULL;
- break;
- }
-
- fi->dnlmax = -1;
- for (i = 0; i < fi->dc; i++) {
- if ((len = strlen(fi->dnl[i])) > fi->dnlmax)
- fi->dnlmax = len;
- }
-
- fi->bnlmax = -1;
- for (i = 0; i < fi->fc; i++) {
- if ((len = strlen(fi->bnl[i])) > fi->bnlmax)
- fi->bnlmax = len;
- }
-
- fi->dperms = 0755;
- fi->fperms = 0644;
-
- return;
-}
-
-void freeFi(TFI_t fi)
-{
- HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
-
- fi->name = _free(fi->name);
- fi->version = _free(fi->version);
- fi->release = _free(fi->release);
- fi->actions = _free(fi->actions);
- fi->replacedSizes = _free(fi->replacedSizes);
- fi->replaced = _free(fi->replaced);
-
- fi->bnl = hfd(fi->bnl, -1);
- fi->dnl = hfd(fi->dnl, -1);
- fi->obnl = hfd(fi->obnl, -1);
- fi->odnl = hfd(fi->odnl, -1);
- fi->flinks = hfd(fi->flinks, -1);
- fi->fmd5s = hfd(fi->fmd5s, -1);
- fi->fuser = hfd(fi->fuser, -1);
- fi->fgroup = hfd(fi->fgroup, -1);
- fi->flangs = hfd(fi->flangs, -1);
-
- fi->apath = _free(fi->apath);
- fi->fuids = _free(fi->fuids);
- fi->fgids = _free(fi->fgids);
- fi->fmapflags = _free(fi->fmapflags);
-
- fi->fsm = freeFSM(fi->fsm);
-
- switch (fi->type) {
- case TR_ADDED:
- break;
- case TR_REMOVED:
- fi->fsizes = hfd(fi->fsizes, -1);
- fi->fflags = hfd(fi->fflags, -1);
- fi->fmodes = hfd(fi->fmodes, -1);
- fi->fstates = hfd(fi->fstates, -1);
- fi->dil = hfd(fi->dil, -1);
- break;
- }
- if (fi->h) {
- headerFree(fi->h); fi->h = NULL;
- }
-}
-
-/*@observer@*/ const char *const fiTypeString(TFI_t fi) {
- switch(fi->type) {
- case TR_ADDED: return " install";
- case TR_REMOVED: return " erase";
- default: return "???";
- }
- /*@noteached@*/
-}
-
-/*@observer@*/ const char *const fileStageString(fileStage a) {
- switch(a) {
- case FSM_UNKNOWN: return "unknown";
-
- case FSM_PKGINSTALL:return "pkginstall";
- case FSM_PKGERASE: return "pkgerase";
- case FSM_PKGBUILD: return "pkgbuild";
- case FSM_PKGCOMMIT: return "pkgcommit";
- case FSM_PKGUNDO: return "pkgundo";
-
- case FSM_CREATE: return "create";
- case FSM_INIT: return "init";
- case FSM_MAP: return "map";
- case FSM_MKDIRS: return "mkdirs";
- case FSM_RMDIRS: return "rmdirs";
- case FSM_PRE: return "pre";
- case FSM_PROCESS: return "process";
- case FSM_POST: return "post";
- case FSM_MKLINKS: return "mklinks";
- case FSM_NOTIFY: return "notify";
- case FSM_UNDO: return "undo";
- case FSM_FINI: return "fini";
- case FSM_COMMIT: return "commit";
- case FSM_DESTROY: return "destroy";
- case FSM_VERIFY: return "verify";
-
- case FSM_UNLINK: return "Unlink";
- case FSM_RENAME: return "Rename";
- case FSM_MKDIR: return "Mkdir";
- case FSM_RMDIR: return "rmdir";
- case FSM_CHOWN: return "chown";
- case FSM_LCHOWN: return "lchown";
- case FSM_CHMOD: return "chmod";
- case FSM_UTIME: return "utime";
- case FSM_SYMLINK: return "symlink";
- case FSM_LINK: return "Link";
- case FSM_MKFIFO: return "mkfifo";
- case FSM_MKNOD: return "mknod";
- case FSM_LSTAT: return "Lstat";
- case FSM_STAT: return "Stat";
- case FSM_READLINK: return "Readlink";
- case FSM_CHROOT: return "chroot";
-
- case FSM_NEXT: return "next";
- case FSM_EAT: return "eat";
- case FSM_POS: return "pos";
- case FSM_PAD: return "pad";
- case FSM_TRAILER: return "trailer";
- case FSM_HREAD: return "hread";
- case FSM_HWRITE: return "hwrite";
- case FSM_DREAD: return "Fread";
- case FSM_DWRITE: return "Fwrite";
-
- case FSM_ROPEN: return "Fopen";
- case FSM_READ: return "Fread";
- case FSM_RCLOSE: return "Fclose";
- case FSM_WOPEN: return "Fopen";
- case FSM_WRITE: return "Fwrite";
- case FSM_WCLOSE: return "Fclose";
-
- default: return "???";
- }
- /*@noteached@*/
-}
-
-/*@obserever@*/ const char *const fileActionString(fileAction a)
-{
- switch (a) {
- case FA_UNKNOWN: return "unknown";
- case FA_CREATE: return "create";
- case FA_BACKUP: return "backup";
- case FA_SAVE: return "save";
- case FA_SKIP: return "skip";
- case FA_ALTNAME: return "altname";
- case FA_ERASE: return "erase";
- case FA_SKIPNSTATE: return "skipnstate";
- case FA_SKIPNETSHARED: return "skipnetshared";
- case FA_SKIPMULTILIB: return "skipmultilib";
- default: return "???";
- }
- /*@notreached@*/
-}
-
-#ifdef DYING
-/**
- */
-struct pkgIterator {
-/*@dependent@*/ /*@kept@*/ TFI_t fi;
- int i;
-};
-
-/**
- */
-static /*@null@*/ void * pkgFreeIterator(/*@only@*/ /*@null@*/ void * this) {
- return _free(this);
-}
-
-/**
- */
-static /*@only@*/ void * pkgInitIterator(/*@kept@*/ rpmTransactionSet ts,
- /*@kept@*/ TFI_t fi)
-{
- struct pkgIterator * pi = NULL;
- if (ts && fi) {
- pi = xcalloc(sizeof(*pi), 1);
- pi->fi = fi;
- switch (fi->type) {
- case TR_ADDED: pi->i = 0; break;
- case TR_REMOVED: pi->i = fi->fc; break;
- }
- }
- return pi;
-}
-
-/**
- */
-static int pkgNextIterator(/*@null@*/ void * this) {
- struct pkgIterator * pi = this;
- int i = -1;
-
- if (pi) {
- TFI_t fi = pi->fi;
- switch (fi->type) {
- case TR_ADDED:
- if (pi->i < fi->fc)
- i = pi->i++;
- break;
- case TR_REMOVED:
- if (pi->i >= 0)
- i = --pi->i;
- break;
- }
- }
- return i;
-}
-
-int pkgActions(const rpmTransactionSet ts, TFI_t fi, fileStage a)
-{
- int rc = 0;
-
- if (fi->actions) {
- void * pi = pkgInitIterator(ts, fi);
- int i;
- while ((i = pkgNextIterator(pi)) != -1) {
- if (pkgAction(ts, fi, i, a))
- rc++;
- }
- pi = pkgFreeIterator(pi);
- }
- return rc;
-}
-#endif
+++ /dev/null
-#ifndef H_ROLLBACK
-#define H_ROLLBACK
-
-/** \file lib/rollback.h
- */
-
-#include "depends.h"
-#include "install.h"
-
-/**
- */
-typedef /*@abstract@*/ struct fsm_s * FSM_t;
-
-#include "cpio.h"
-
-/**
- */
-#define FSM_VERBOSE 0x8000
-#define FSM_INTERNAL 0x4000
-#define FSM_SYSCALL 0x2000
-#define FSM_DEAD 0x1000
-#define _fv(_a) ((_a) | FSM_VERBOSE)
-#define _fi(_a) ((_a) | FSM_INTERNAL)
-#define _fs(_a) ((_a) | (FSM_INTERNAL | FSM_SYSCALL))
-#define _fd(_a) ((_a) | (FSM_INTERNAL | FSM_DEAD))
-typedef enum fileStage_e {
- FSM_UNKNOWN = 0,
- FSM_INIT = _fd(1),
- FSM_PRE = _fd(2),
- FSM_PROCESS = _fv(3),
- FSM_POST = _fd(4),
- FSM_UNDO = 5,
- FSM_FINI = 6,
-
- FSM_PKGINSTALL = _fd(7),
- FSM_PKGERASE = _fd(8),
- FSM_PKGBUILD = _fd(9),
- FSM_PKGCOMMIT = _fd(10),
- FSM_PKGUNDO = _fd(11),
-
- FSM_CREATE = _fd(17),
- FSM_MAP = _fd(18),
- FSM_MKDIRS = _fi(19),
- FSM_RMDIRS = _fi(20),
- FSM_MKLINKS = _fi(21),
- FSM_NOTIFY = _fd(22),
- FSM_DESTROY = _fd(23),
- FSM_VERIFY = _fd(24),
- FSM_COMMIT = _fd(25),
-
- FSM_UNLINK = _fs(33),
- FSM_RENAME = _fs(34),
- FSM_MKDIR = _fs(35),
- FSM_RMDIR = _fs(36),
- FSM_CHOWN = _fs(37),
- FSM_LCHOWN = _fs(38),
- FSM_CHMOD = _fs(39),
- FSM_UTIME = _fs(40),
- FSM_SYMLINK = _fs(41),
- FSM_LINK = _fs(42),
- FSM_MKFIFO = _fs(43),
- FSM_MKNOD = _fs(44),
- FSM_LSTAT = _fs(45),
- FSM_STAT = _fs(46),
- FSM_READLINK= _fs(47),
- FSM_CHROOT = _fs(48),
-
- FSM_NEXT = _fd(65),
- FSM_EAT = _fd(66),
- FSM_POS = _fd(67),
- FSM_PAD = _fd(68),
- FSM_TRAILER = _fd(69),
- FSM_HREAD = _fd(70),
- FSM_HWRITE = _fd(71),
- FSM_DREAD = _fs(72),
- FSM_DWRITE = _fs(73),
-
- FSM_ROPEN = _fs(129),
- FSM_READ = _fs(130),
- FSM_RCLOSE = _fs(131),
- FSM_WOPEN = _fs(132),
- FSM_WRITE = _fs(133),
- FSM_WCLOSE = _fs(134),
-} fileStage;
-#undef _fi
-
-/**
- * File disposition(s) during package install/erase transaction.
- */
-typedef enum fileAction_e {
- FA_UNKNOWN = 0, /*!< initial action (default action for source rpm) */
- FA_CREATE, /*!< ... to be replaced. */
- FA_BACKUP, /*!< ... renamed with ".rpmorig" extension. */
- FA_SAVE, /*!< ... renamed with ".rpmsave" extension. */
- FA_SKIP, /*!< ... already replaced, don't remove. */
- FA_ALTNAME, /*!< ... create with ".rpmnew" extension. */
- FA_ERASE, /*!< ... to be removed. */
- FA_SKIPNSTATE, /*!< ... untouched, state "not installed". */
- FA_SKIPNETSHARED, /*!< ... untouched, state "netshared". */
- FA_SKIPMULTILIB, /*!< ... untouched. @todo state "multilib" ???. */
-} fileAction;
-
-
-#define XFA_SKIPPING(_a) \
- ((_a) == FA_SKIP || (_a) == FA_SKIPNSTATE || (_a) == FA_SKIPNETSHARED || (_a) == FA_SKIPMULTILIB)
-
-/**
- */
-typedef enum rollbackDir_e {
- ROLLBACK_SAVE = 1, /*!< Save files. */
- ROLLBACK_RESTORE = 2, /*!< Restore files. */
-} rollbackDir;
-
-/**
- * File types.
- * These are the types of files used internally by rpm. The file
- * type is determined by applying stat(2) macros like S_ISDIR to
- * the file mode tag from a header. The values are arbitrary,
- * but are identical to the linux stat(2) file types.
- */
-enum fileTypes {
- PIPE = 1, /*!< pipe/fifo */
- CDEV = 2, /*!< character device */
- XDIR = 4, /*!< directory */
- BDEV = 6, /*!< block device */
- REG = 8, /*!< regular file */
- LINK = 10, /*!< hard link */
- SOCK = 12, /*!< socket */
-};
-
-/**
- */
-struct transactionFileInfo_s {
- /* for all packages */
- enum rpmTransactionType type;
- fileAction action; /*!< File disposition default. */
-/*@owned@*/ fileAction * actions; /*!< File disposition(s) */
-/*@owned@*/ struct fingerPrint_s * fps; /*!< File fingerprint(s) */
- HGE_t hge; /*!< Vector to headerGetEntry() */
- HFD_t hfd; /*!< Vector to headerFreeData() */
- Header h; /*!< Package header */
-/*@owned@*/ const char * name;
-/*@owned@*/ const char * version;
-/*@owned@*/ const char * release;
- int_32 epoch;
- uint_32 flags; /*!< File flag default. */
- const uint_32 * fflags; /*!< File flag(s) (from header) */
- const uint_32 * fsizes; /*!< File size(s) (from header) */
- const uint_32 * fmtimes; /*!< File modification time(s) (from header) */
-/*@owned@*/ const char ** bnl; /*!< Base name(s) (from header) */
-/*@owned@*/ const char ** dnl; /*!< Directory name(s) (from header) */
- int_32 * dil; /*!< Directory indice(s) (from header) */
-/*@owned@*/ const char ** obnl; /*!< Original base name(s) (from header) */
-/*@owned@*/ const char ** odnl; /*!< Original directory name(s) (from header) */
- int_32 * odil; /*!< Original directory indice(s) (from header) */
-/*@owned@*/ const char ** fmd5s;/*!< File MD5 sum(s) (from header) */
-/*@owned@*/ const char ** flinks; /*!< File link(s) (from header) */
-/* XXX setuid/setgid bits are turned off if fuser/fgroup doesn't map. */
- uint_16 * fmodes; /*!< File mode(s) (from header) */
-/*@owned@*/ char * fstates; /*!< File state(s) (from header) */
-/*@owned@*/ const char ** fuser; /*!< File owner(s) */
-/*@owned@*/ const char ** fgroup; /*!< File group(s) */
-/*@owned@*/ const char ** flangs; /*!< File lang(s) */
- int fc; /*!< No. of files. */
- int dc; /*!< No. of directories. */
- int bnlmax; /*!< Length (in bytes) of longest base name. */
- int dnlmax; /*!< Length (in bytes) of longest dir name. */
- int astriplen;
- int striplen;
- int scriptArg;
- unsigned int archiveSize;
- mode_t dperms; /*!< Directory perms (0755) if not mapped. */
- mode_t fperms; /*!< File perms (0644) if not mapped. */
-/*@owned@*/ const char ** apath;
- int mapflags;
-/*@owned@*/ int * fmapflags;
- uid_t uid;
-/*@owned@*/ /*@null@*/ uid_t * fuids; /*!< File uid(s) */
- gid_t gid;
-/*@owned@*/ /*@null@*/ gid_t * fgids; /*!< File gid(s) */
- int magic;
-#define TFIMAGIC 0x09697923
-/*@owned@*/ FSM_t fsm; /*!< File state machine data. */
-
- /* these are for TR_ADDED packages */
-/*@dependent@*/ struct availablePackage * ap;
-/*@owned@*/ struct sharedFileInfo * replaced;
-/*@owned@*/ uint_32 * replacedSizes;
- /* for TR_REMOVED packages */
- unsigned int record;
-};
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * Create file state machine instance.
- * @return file state machine data
- */
-/*@only@*/ /*@null@*/ FSM_t newFSM(void);
-
-/**
- * Destroy file state machine instance.
- * @param fsm file state machine data
- * @return always NULL
- */
-/*@null@*/ FSM_t freeFSM(/*@only@*/ /*@null@*/ FSM_t fsm);
-
-/**
- * Load data from header into transaction file element info.
- * @param h header
- * @param fi transaction element file info
- */
-void loadFi(Header h, TFI_t fi)
- /*@modifies h, fi @*/;
-
-/**
- * Destroy transaction element file info.
- * @param fi transaction element file info
- */
-void freeFi(TFI_t fi)
- /*@modifies fi @*/;
-
-/**
- * Return formatted string representation of package disposition.
- * @param a package dispostion
- * @return formatted string
- */
-/*@observer@*/ const char *const fiTypeString(TFI_t fi);
-
-/**
- * Return formatted string representation of file stages.
- * @param a file stage
- * @return formatted string
- */
-/*@observer@*/ const char *const fileStageString(fileStage a);
-
-/**
- * Return formatted string representation of file disposition.
- * @param a file dispostion
- * @return formatted string
- */
-/*@observer@*/ const char *const fileActionString(fileAction a);
-
-#ifdef DYING
-/**
- * Perform package install/remove actions for s single file.
- * @todo Eliminate.
- * @param ts transaction set
- * @param fi transaction element file info
- * @param i file index
- * @param a file stage
- * @return 0 on success, 1 on failure
- */
-int pkgAction(const rpmTransactionSet ts, TFI_t fi, int i, fileStage a);
-
-/**
- * Perform package pre-install and remove actions.
- * @todo Eliminate.
- * @param ts transaction set
- * @param fi transaction element file info
- * @param a file stage
- * @return 0 on success, otherwise no. of failures
- */
-int pkgActions(const rpmTransactionSet ts, TFI_t fi, fileStage a);
-#endif
-
-/**
- * Load external data into file state machine.
- * @param fsm file state machine data
- * @param goal
- * @param ts transaction set
- * @param fi transaction element file info
- * @param archiveSize pointer to archive size
- * @param failedFile pointer to first file name that failed.
- * @return 0 on success
- */
-int fsmSetup(FSM_t fsm, fileStage goal,
- /*@kept@*/ const rpmTransactionSet ts,
- /*@kept@*/ const TFI_t fi,
- FD_t cfd,
- /*@out@*/ unsigned int * archiveSize,
- /*@out@*/ const char ** failedFile)
- /*@modifies fsm, *archiveSize, *failedFile @*/;
-
-/**
- * Clean file state machine.
- * @param fsm file state machine data
- * @return 0 on success
- */
-int fsmTeardown(FSM_t fsm)
- /*@modifies fsm @*/;
-
-/**
- * Retrieve transaction set from file state machine iterator.
- * @param fsm file state machine data
- * @return transaction set
- */
-/*@kept@*/ rpmTransactionSet fsmGetTs(const FSM_t fsm) /*@*/;
-
-/**
- * Retrieve transaction element file info from file state machine iterator.
- * @param fsm file state machine data
- * @return transaction element file info
- */
-/*@kept@*/ TFI_t fsmGetFi(const FSM_t fsm) /*@*/;
-
-/**
- * Map next file path and action.
- * @param fsm file state machine data
- */
-int fsmMapPath(FSM_t fsm)
- /*@modifies fsm @*/;
-
-/**
- * Map file stat(2) info.
- * @param fsm file state machine data
- */
-int fsmMapAttrs(FSM_t fsm)
- /*@modifies fsm @*/;
-
-/**
- * File state machine driver.
- * @param fsm file state machine data
- * @param stage next stage
- * @return 0 on success
- */
-int fsmStage(FSM_t fsm, fileStage stage)
- /*@modifies fsm @*/;
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* H_ROLLBACK */
*/
int rpmVersionCompare(Header first, Header second);
+/**
+ * File disposition(s) during package install/erase transaction.
+ */
+typedef enum fileAction_e {
+ FA_UNKNOWN = 0, /*!< initial action for file ... */
+ FA_CREATE, /*!< ... to be replaced. */
+ FA_BACKUP, /*!< ... renamed with ".rpmorig" extension. */
+ FA_SAVE, /*!< ... renamed with ".rpmsave" extension. */
+ FA_SKIP, /*!< ... already replaced, don't remove. */
+ FA_ALTNAME, /*!< ... create with ".rpmnew" extension. */
+ FA_ERASE, /*!< ... to be removed. */
+ FA_SKIPNSTATE, /*!< ... untouched, state "not installed". */
+ FA_SKIPNETSHARED, /*!< ... untouched, state "netshared". */
+ FA_SKIPMULTILIB, /*!< ... untouched. @todo state "multilib" ???. */
+} fileAction;
+
+#define XFA_SKIPPING(_a) \
+ ((_a) == FA_SKIP || (_a) == FA_SKIPNSTATE || (_a) == FA_SKIPNETSHARED || (_a) == FA_SKIPMULTILIB)
+
+/**
+ * File types.
+ * These are the types of files used internally by rpm. The file
+ * type is determined by applying stat(2) macros like S_ISDIR to
+ * the file mode tag from a header. The values are arbitrary,
+ * but are identical to the linux stat(2) file types.
+ */
+typedef enum fileTypes_e {
+ PIPE = 1, /*!< pipe/fifo */
+ CDEV = 2, /*!< character device */
+ XDIR = 4, /*!< directory */
+ BDEV = 6, /*!< block device */
+ REG = 8, /*!< regular file */
+ LINK = 10, /*!< hard link */
+ SOCK = 12, /*!< socket */
+} fileTypes;
+
+/** \ingroup payload
+ * Iterator across package file info, forward on install, backward on erase.
+ */
+typedef /*@abstract@*/ struct fsmIterator_s * FSMI_t;
+
+/** \ingroup payload
+ * File state machine data.
+ */
+typedef /*@abstract@*/ struct fsm_s * FSM_t;
+
+/** \ingroup rpmtrans
+ */
+typedef /*@abstract@*/ struct transactionFileInfo_s * TFI_t;
+
/** \ingroup rpmtrans
* The RPM Transaction Set.
* Transaction sets are inherently unordered! RPM may reorder transaction
--- /dev/null
+/** \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 "scriptlet.h"
+#include "misc.h" /* XXX for makeTempFile, doputenv */
+#include "debug.h"
+
+/*@access Header@*/ /* XXX compared with NULL */
+
+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 ts transaction set
+ * @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(const rpmTransactionSet ts, Header h,
+ const char * sln,
+ int progArgc, const char ** progArgv,
+ const char * script, int arg1, int arg2)
+{
+ const char ** argv = NULL;
+ int argc = 0;
+ const char ** prefixes = NULL;
+ int numPrefixes;
+ 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 (headerGetEntry(h, RPMTAG_INSTPREFIXES, NULL, (void **) &prefixes,
+ &numPrefixes)) {
+ freePrefixes = 1;
+ } else if (headerGetEntry(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) free(prefixes);
+
+ Fclose(out); /* XXX dup'd STDOUT_FILENO */
+
+ if (script) {
+ if (!rpmIsDebug()) unlink(fn);
+ free((void *)fn);
+ }
+
+ return rc;
+}
+
+int runInstScript(const rpmTransactionSet ts, Header h,
+ int scriptTag, int progTag, int arg, int norunScripts)
+{
+ void ** programArgv;
+ int programArgc;
+ const char ** argv;
+ int programType;
+ char * script;
+ int rc;
+
+ if (norunScripts) return 0;
+
+ /* headerGetEntry() sets the data pointer to NULL if the entry does
+ not exist */
+ headerGetEntry(h, progTag, &programType, (void **) &programArgv,
+ &programArgc);
+ headerGetEntry(h, scriptTag, NULL, (void **) &script, NULL);
+
+ if (programArgv && programType == RPM_STRING_TYPE) {
+ argv = alloca(sizeof(char *));
+ *argv = (const char *) programArgv;
+ } else {
+ argv = (const char **) programArgv;
+ }
+
+ rc = runScript(ts, h, tag2sln(scriptTag), programArgc, argv, script,
+ arg, -1);
+ programArgv = headerFreeData(programArgv, programType);
+ return rc;
+}
+
+/**
+ * @param ts transaction set
+ * @param sense
+ * @param sourceH
+ * @param triggeredH
+ * @param arg1correction
+ * @param arg2
+ * @param triggersAlreadyRun
+ * @return
+ */
+static int handleOneTrigger(const rpmTransactionSet ts, int sense,
+ Header sourceH, Header triggeredH,
+ int arg1correction, int arg2,
+ char * triggersAlreadyRun)
+{
+ const char ** triggerNames;
+ const char ** triggerEVR;
+ const char ** triggerScripts;
+ const char ** triggerProgs;
+ int_32 * triggerFlags;
+ int_32 * triggerIndices;
+ const char * triggerPackageName;
+ const char * sourceName;
+ int numTriggers;
+ int rc = 0;
+ int i;
+ int skip;
+
+ if (!headerGetEntry(triggeredH, RPMTAG_TRIGGERNAME, NULL,
+ (void **) &triggerNames, &numTriggers)) {
+ return 0;
+ }
+
+ headerNVR(sourceH, &sourceName, NULL, NULL);
+
+ headerGetEntry(triggeredH, RPMTAG_TRIGGERFLAGS, NULL,
+ (void **) &triggerFlags, NULL);
+ headerGetEntry(triggeredH, RPMTAG_TRIGGERVERSION, NULL,
+ (void **) &triggerEVR, NULL);
+
+ for (i = 0; i < numTriggers; i++) {
+
+ if (!(triggerFlags[i] & 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;
+
+ headerGetEntry(triggeredH, RPMTAG_TRIGGERINDEX, NULL,
+ (void **) &triggerIndices, NULL);
+ headerGetEntry(triggeredH, RPMTAG_TRIGGERSCRIPTS, NULL,
+ (void **) &triggerScripts, NULL);
+ headerGetEntry(triggeredH, RPMTAG_TRIGGERSCRIPTPROG, NULL,
+ (void **) &triggerProgs, NULL);
+
+ headerNVR(triggeredH, &triggerPackageName, NULL, NULL);
+
+ { int arg1;
+ int index;
+
+ if ((arg1 = rpmdbCountPackages(ts->rpmdb, triggerPackageName)) < 0) {
+ rc = 1; /* XXX W2DO? same as "execution of script failed" */
+ } else {
+ arg1 += arg1correction;
+ index = triggerIndices[i];
+ if (!triggersAlreadyRun || !triggersAlreadyRun[index]) {
+ rc = runScript(ts, triggeredH, "%trigger", 1,
+ triggerProgs + index, triggerScripts[index],
+ arg1, arg2);
+ if (triggersAlreadyRun) triggersAlreadyRun[index] = 1;
+ }
+ }
+ }
+
+ free(triggerScripts);
+ free(triggerProgs);
+
+ /* each target/source header pair can only result in a single
+ script being run */
+ break;
+ }
+
+ free(triggerNames);
+
+ return rc;
+}
+
+int runTriggers(const rpmTransactionSet ts, int sense, Header h,
+ int countCorrection)
+{
+ const char * name;
+ int numPackage;
+ int rc = 0;
+
+ headerNVR(h, &name, NULL, NULL);
+
+ numPackage = rpmdbCountPackages(ts->rpmdb, name) + countCorrection;
+ if (numPackage < 0)
+ return 1;
+
+ { Header triggeredH;
+ rpmdbMatchIterator mi;
+
+ mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_TRIGGERNAME, name, 0);
+ while((triggeredH = rpmdbNextIterator(mi)) != NULL) {
+ rc |= handleOneTrigger(ts, sense, h, triggeredH, 0, numPackage,
+ NULL);
+ }
+
+ rpmdbFreeIterator(mi);
+ }
+
+ return rc;
+}
+
+int runImmedTriggers(const rpmTransactionSet ts, int sense, Header h,
+ int countCorrection)
+{
+ const char ** triggerNames;
+ int numTriggers;
+ int_32 * triggerIndices;
+ int numTriggerIndices;
+ char * triggersRun;
+ int rc = 0;
+
+ if (!headerGetEntry(h, RPMTAG_TRIGGERNAME, NULL, (void **) &triggerNames,
+ &numTriggers))
+ return 0;
+ headerGetEntry(h, RPMTAG_TRIGGERINDEX, NULL, (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;
+ const char * name = triggerNames[i];
+
+ if (triggersRun[triggerIndices[i]]) continue;
+
+ mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_NAME, name, 0);
+
+ while((sourceH = rpmdbNextIterator(mi)) != NULL) {
+ rc |= handleOneTrigger(ts, sense, sourceH, h,
+ countCorrection, rpmdbGetIteratorCount(mi),
+ triggersRun);
+ }
+
+ rpmdbFreeIterator(mi);
+ }
+ }
+ return rc;
+}
-#ifndef H_INSTALL
-#define H_INSTALL
+#ifndef H_SCRIPTLET
+#define H_SCRIPTLET
-/** \file lib/install.h
+/** \file lib/scriptlet.h
*/
#include <rpmlib.h>
-/**
- */
-struct sharedFile {
- int mainFileNumber;
- int secRecOffset;
- int secFileNumber;
-} ;
-
-/**
- */
-struct sharedFileInfo {
- int pkgFileNum;
- int otherFileNum;
- int otherPkg;
- int isRemoved;
-};
-
-/**
- */
-typedef /*@abstract@*/ struct transactionFileInfo_s * TFI_t;
-
#ifdef __cplusplus
extern "C" {
#endif
int runImmedTriggers(const rpmTransactionSet ts, int sense, Header h,
int countCorrection);
-/**
- * Install binary package (from transaction set).
- * @param ts transaction set
- * @param fi transaction element file info
- * @return 0 on success, 1 on bad magic, 2 on error
- */
-int installBinaryPackage(const rpmTransactionSet ts, TFI_t fi);
-
-/**
- * Erase binary package (from transaction set).
- * @param ts transaction set
- * @param fi transaction element file info
- * @param pkgKey package private data
- * @return 0 on success
- */
-int removeBinaryPackage(const rpmTransactionSet ts, TFI_t fi);
-
#ifdef __cplusplus
}
#endif
-#endif /* H_INSTALL */
+#endif /* H_SCRIPTLET */
#include <rpmlib.h>
#include <rpmmacro.h> /* XXX for rpmExpand */
-#include "rollback.h"
+#include "psm.h"
#include "fprint.h"
#include "hash.h"
#include "md5.h"
free(probs);
}
-static /*@observer@*/ const char *const ftstring (enum fileTypes ft)
+static /*@observer@*/ const char *const ftstring (fileTypes ft)
{
switch (ft) {
case XDIR: return "directory";
/*@notreached@*/
}
-static enum fileTypes whatis(uint_16 mode)
+static fileTypes whatis(uint_16 mode)
{
if (S_ISDIR(mode)) return XDIR;
if (S_ISCHR(mode)) return CDEV;
/* On install, a relocate to NULL means skip the path. */
if (relocations[j].newPath == NULL) {
- enum fileTypes ft = whatis(fModes[i]);
+ fileTypes ft = whatis(fModes[i]);
int k;
if (ft == XDIR) {
/* Start with the parent, looking for directory to exclude. */
{
char buffer[1024];
const char * dbAttr, * newAttr;
- enum fileTypes dbWhat, newWhat, diskWhat;
+ fileTypes dbWhat, newWhat, diskWhat;
struct stat sb;
int i, rc;
int save = (newFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SAVE;
static int filecmp(short mode1, const char * md51, const char * link1,
short mode2, const char * md52, const char * link2)
{
- enum fileTypes what1 = whatis(mode1);
- enum fileTypes what2 = whatis(mode2);
+ fileTypes what1 = whatis(mode1);
+ fileTypes what2 = whatis(mode2);
if (what1 != what2) return 1;
+++ /dev/null
-/** \ingroup rpmtrans payload
- * \file lib/uninstall.c
- */
-
-#include "system.h"
-
-#include <rpmlib.h>
-#include <rpmurl.h>
-#include <rpmmacro.h> /* XXX for rpmExpand */
-
-#include "rollback.h"
-#include "misc.h" /* XXX for makeTempFile, doputenv */
-#include "debug.h"
-
-/*@access Header@*/ /* XXX compared with NULL */
-
-int removeBinaryPackage(const rpmTransactionSet ts, TFI_t fi)
-{
-/*@observer@*/ static char * stepName = " erase";
- Header h;
- int chrootDone = 0;
- const char * failedFile = NULL;
- const void * pkgKey = NULL;
- int rc = 0;
-
- rpmMessage(RPMMESS_DEBUG, _("%s: %s-%s-%s has %d files, test = %d\n"),
- stepName, fi->name, fi->version, fi->release,
- fi->fc, (ts->transFlags & RPMTRANS_FLAG_TEST));
-
- /*
- * When we run scripts, we pass an argument which is the number of
- * versions of this package that will be installed when we are finished.
- */
- fi->scriptArg = rpmdbCountPackages(ts->rpmdb, fi->name) - 1;
- if (fi->scriptArg < 0)
- return 1;
-
- { rpmdbMatchIterator mi = NULL;
-
- mi = rpmdbInitIterator(ts->rpmdb, RPMDBI_PACKAGES,
- &fi->record, sizeof(fi->record));
-
- h = rpmdbNextIterator(mi);
- if (h == NULL) {
- rpmdbFreeIterator(mi);
- return 2;
- }
- h = headerLink(h);
- rpmdbFreeIterator(mi);
- }
-
- if (ts->rootDir && !ts->chrootDone) {
- chdir("/");
- /*@-unrecog@*/ chroot(ts->rootDir); /*@=unrecog@*/
- chrootDone = ts->chrootDone = 1;
- }
-
- if (!(ts->transFlags & RPMTRANS_FLAG_NOTRIGGERS)) {
- /* run triggers from this package which are keyed on installed
- packages */
- if (runImmedTriggers(ts, RPMSENSE_TRIGGERUN, h, -1))
- return 2;
-
- /* run triggers which are set off by the removal of this package */
- if (runTriggers(ts, RPMSENSE_TRIGGERUN, h, -1))
- return 1;
- }
-
- rpmMessage(RPMMESS_DEBUG, _("%s: running %s script(s) (if any)\n"),
- stepName, "pre-erase");
-
- rc = runInstScript(ts, h, RPMTAG_PREUN, RPMTAG_PREUNPROG, fi->scriptArg,
- (ts->transFlags & RPMTRANS_FLAG_NOSCRIPTS));
- if (rc)
- return 1;
-
- if (fi->fc > 0 && !(ts->transFlags & RPMTRANS_FLAG_JUSTDB)) {
-
- if (ts->notify)
- (void)ts->notify(h, RPMCALLBACK_UNINST_START, fi->fc, fi->fc,
- pkgKey, ts->notifyData);
-
- rc = fsmSetup(fi->fsm, FSM_PKGERASE, ts, fi, NULL, NULL, &failedFile);
- (void) fsmTeardown(fi->fsm);
-
- if (ts->notify)
- (void)ts->notify(h, RPMCALLBACK_UNINST_STOP, 0, fi->fc,
- pkgKey, ts->notifyData);
- }
-
- rpmMessage(RPMMESS_DEBUG, _("%s: running %s script(s) (if any)\n"),
- stepName, "post-erase");
-
- rc = runInstScript(ts, h, RPMTAG_POSTUN, RPMTAG_POSTUNPROG,
- fi->scriptArg, (ts->transFlags & RPMTRANS_FLAG_NOSCRIPTS));
- /* XXX postun failures are not cause for erasure failure. */
-
- if (!(ts->transFlags & RPMTRANS_FLAG_NOTRIGGERS)) {
- /* Run postun triggers which are set off by this package's removal. */
- rc = runTriggers(ts, RPMSENSE_TRIGGERPOSTUN, h, -1);
- if (rc)
- return 2;
- }
-
- if (ts->rootDir && chrootDone) {
- /*@-unrecog@*/ chroot("."); /*@=unrecog@*/
- chrootDone = ts->chrootDone = 0;
- chdir(ts->currDir);
- }
-
- if (!(ts->transFlags & RPMTRANS_FLAG_TEST))
- rpmdbRemove(ts->rpmdb, ts->id, fi->record);
-
- return 0;
-}
#include "system.h"
#include <rpmlib.h>
-#include <rpmbuild.h>
#include <rpmurl.h>
-#include "depends.h"
-#include "install.h"
+#include "psm.h"
#include "md5.h"
#include "misc.h"
#include "debug.h"
lib/formats.c
lib/fprint.c
lib/fs.c
+lib/fsm.c
lib/hash.c
lib/header.c
-lib/install.c
lib/md5.c
lib/md5sum.c
lib/misc.c
lib/poptBT.c
lib/poptQV.c
lib/problems.c
+lib/psm.c
lib/query.c
-lib/rollback.c
lib/rpmchecksig.c
lib/rpmdb.c
lib/rpminstall.c
lib/signature.c
lib/stringbuf.c
lib/transaction.c
-lib/uninstall.c
lib/verify.c
rpmio/base64.c
rpmio/digest.c
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
-"POT-Creation-Date: 2001-02-10 09:07-0500\n"
+"POT-Creation-Date: 2001-02-10 11:46-0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: ENCODING\n"
-#: build.c:26
+#: build.c:25
#, c-format
msgid "cannot open rpm database in %s\n"
msgstr ""
-#: build.c:36
+#: build.c:35
msgid "failed build dependencies:\n"
msgstr ""
-#: build.c:65
+#: build.c:64
#, c-format
msgid "Unable to open spec file %s: %s\n"
msgstr ""
-#: build.c:132 build.c:144
+#: build.c:131 build.c:143
#, c-format
msgid "Failed to open tar pipe: %m\n"
msgstr ""
#. Give up
-#: build.c:151
+#: build.c:150
#, c-format
msgid "Failed to read spec file from %s\n"
msgstr ""
-#: build.c:179
+#: build.c:178
#, c-format
msgid "Failed to rename %s to %s: %m\n"
msgstr ""
-#: build.c:218
+#: build.c:217
#, c-format
msgid "failed to stat %s: %m\n"
msgstr ""
-#: build.c:223
+#: build.c:222
#, c-format
msgid "File %s is not a regular file.\n"
msgstr ""
-#: build.c:232
+#: build.c:231
#, c-format
msgid "File %s does not appear to be a specfile.\n"
msgstr ""
#. parse up the build operators
-#: build.c:289
+#: build.c:288
#, c-format
msgid "Building target platforms: %s\n"
msgstr ""
-#: build.c:304
+#: build.c:303
#, c-format
msgid "Building for target %s\n"
msgstr ""
-#: rpm.c:201 rpmqv.c:357
+#: rpm.c:200 rpmqv.c:356
#, c-format
msgid "rpm: %s\n"
msgstr ""
-#: rpm.c:212 rpmqv.c:362
+#: rpm.c:211 rpmqv.c:361
#, c-format
msgid "RPM version %s\n"
msgstr ""
-#: rpm.c:216 rpmqv.c:366
+#: rpm.c:215 rpmqv.c:365
msgid "Copyright (C) 1998-2000 - Red Hat, Inc."
msgstr ""
-#: rpm.c:217 rpmqv.c:367
+#: rpm.c:216 rpmqv.c:366
msgid "This program may be freely redistributed under the terms of the GNU GPL"
msgstr ""
-#: rpm.c:225
+#: rpm.c:224
msgid "Usage: rpm {--help}"
msgstr ""
-#: rpm.c:226
+#: rpm.c:225
msgid " rpm {--version}"
msgstr ""
-#: rpm.c:227
+#: rpm.c:226
msgid " rpm {--initdb} [--dbpath <dir>]"
msgstr ""
-#: rpm.c:228
+#: rpm.c:227
msgid ""
" rpm {--install -i} [-v] [--hash -h] [--percent] [--force] [--test]"
msgstr ""
-#: rpm.c:229
+#: rpm.c:228
msgid " [--replacepkgs] [--replacefiles] [--root <dir>]"
msgstr ""
-#: rpm.c:230
+#: rpm.c:229
msgid " [--excludedocs] [--includedocs] [--noscripts]"
msgstr ""
-#: rpm.c:231
+#: rpm.c:230
msgid ""
" [--rcfile <file>] [--ignorearch] [--dbpath <dir>]"
msgstr ""
-#: rpm.c:232
+#: rpm.c:231
msgid ""
" [--prefix <dir>] [--ignoreos] [--nodeps] [--allfiles]"
msgstr ""
-#: rpm.c:233 rpm.c:242 rpm.c:252
+#: rpm.c:232 rpm.c:241 rpm.c:251
msgid " [--ftpproxy <host>] [--ftpport <port>]"
msgstr ""
-#: rpm.c:234 rpm.c:253
+#: rpm.c:233 rpm.c:252
msgid " [--httpproxy <host>] [--httpport <port>]"
msgstr ""
-#: rpm.c:235
+#: rpm.c:234
msgid ""
" [--justdb] [--noorder] [--relocate oldpath=newpath]"
msgstr ""
-#: rpm.c:236
+#: rpm.c:235
msgid ""
" [--badreloc] [--notriggers] [--excludepath <path>]"
msgstr ""
-#: rpm.c:237
+#: rpm.c:236
msgid " [--ignoresize] file1.rpm ... fileN.rpm"
msgstr ""
-#: rpm.c:238
+#: rpm.c:237
msgid ""
" rpm {--upgrade -U} [-v] [--hash -h] [--percent] [--force] [--test]"
msgstr ""
-#: rpm.c:239
+#: rpm.c:238
msgid " [--oldpackage] [--root <dir>] [--noscripts]"
msgstr ""
-#: rpm.c:240
+#: rpm.c:239
msgid ""
" [--excludedocs] [--includedocs] [--rcfile <file>]"
msgstr ""
-#: rpm.c:241
+#: rpm.c:240
msgid ""
" [--ignorearch] [--dbpath <dir>] [--prefix <dir>] "
msgstr ""
-#: rpm.c:243
+#: rpm.c:242
msgid " [--httpproxy <host>] [--httpport <port>] "
msgstr ""
-#: rpm.c:244
+#: rpm.c:243
msgid " [--ignoreos] [--nodeps] [--allfiles] [--justdb]"
msgstr ""
-#: rpm.c:245
+#: rpm.c:244
msgid " [--noorder] [--relocate oldpath=newpath]"
msgstr ""
-#: rpm.c:246
+#: rpm.c:245
msgid ""
" [--badreloc] [--excludepath <path>] [--ignoresize]"
msgstr ""
-#: rpm.c:247
+#: rpm.c:246
msgid " file1.rpm ... fileN.rpm"
msgstr ""
-#: rpm.c:248
+#: rpm.c:247
msgid " rpm {--query -q} [-afpg] [-i] [-l] [-s] [-d] [-c] [-v] [-R]"
msgstr ""
-#: rpm.c:249
+#: rpm.c:248
msgid " [--scripts] [--root <dir>] [--rcfile <file>]"
msgstr ""
-#: rpm.c:250
+#: rpm.c:249
msgid " [--whatprovides] [--whatrequires] [--requires]"
msgstr ""
-#: rpm.c:251
+#: rpm.c:250
msgid " [--triggeredby]"
msgstr ""
-#: rpm.c:254
+#: rpm.c:253
msgid " [--provides] [--triggers] [--dump]"
msgstr ""
-#: rpm.c:255
+#: rpm.c:254
msgid " [--changelog] [--dbpath <dir>] [targets]"
msgstr ""
-#: rpm.c:256
+#: rpm.c:255
msgid " rpm {--verify -V -y} [-afpg] [--root <dir>] [--rcfile <file>]"
msgstr ""
-#: rpm.c:257
+#: rpm.c:256
msgid ""
" [--dbpath <dir>] [--nodeps] [--nofiles] [--noscripts]"
msgstr ""
-#: rpm.c:258
+#: rpm.c:257
msgid " [--nomd5] [targets]"
msgstr ""
-#: rpm.c:259
+#: rpm.c:258
msgid " rpm {--setperms} [-afpg] [target]"
msgstr ""
-#: rpm.c:260
+#: rpm.c:259
msgid " rpm {--setugids} [-afpg] [target]"
msgstr ""
-#: rpm.c:261
+#: rpm.c:260
msgid " rpm {--freshen -F} file1.rpm ... fileN.rpm"
msgstr ""
-#: rpm.c:262
+#: rpm.c:261
msgid " rpm {--erase -e} [--root <dir>] [--noscripts] [--rcfile <file>]"
msgstr ""
-#: rpm.c:263
+#: rpm.c:262
msgid " [--dbpath <dir>] [--nodeps] [--allmatches]"
msgstr ""
-#: rpm.c:264
+#: rpm.c:263
msgid " [--justdb] [--notriggers] package1 ... packageN"
msgstr ""
-#: rpm.c:265
+#: rpm.c:264
msgid " rpm {--resign} [--rcfile <file>] package1 package2 ... packageN"
msgstr ""
-#: rpm.c:266
+#: rpm.c:265
msgid " rpm {--addsign} [--rcfile <file>] package1 package2 ... packageN"
msgstr ""
-#: rpm.c:267
+#: rpm.c:266
msgid ""
" rpm {--checksig -K} [--nopgp] [--nogpg] [--nomd5] [--rcfile <file>]"
msgstr ""
-#: rpm.c:268
+#: rpm.c:267
msgid " package1 ... packageN"
msgstr ""
-#: rpm.c:269
+#: rpm.c:268
msgid " rpm {--rebuilddb} [--rcfile <file>] [--dbpath <dir>]"
msgstr ""
-#: rpm.c:270
+#: rpm.c:269
msgid " rpm {--querytags}"
msgstr ""
-#: rpm.c:304 rpmqv.c:442
+#: rpm.c:303 rpmqv.c:441
msgid "Usage:"
msgstr ""
-#: rpm.c:306 rpmqv.c:444
+#: rpm.c:305 rpmqv.c:443
msgid "print this message"
msgstr ""
-#: rpm.c:308 rpmqv.c:129 rpmqv.c:446
+#: rpm.c:307 rpmqv.c:128 rpmqv.c:445
msgid "print the version of rpm being used"
msgstr ""
-#: rpm.c:311
+#: rpm.c:310
msgid " All modes support the following arguments:"
msgstr ""
-#: rpm.c:312
+#: rpm.c:311
msgid " --define '<name> <body>'"
msgstr ""
-#: rpm.c:313 rpmqv.c:136 rpmqv.c:451
+#: rpm.c:312 rpmqv.c:135 rpmqv.c:450
msgid "define macro <name> with value <body>"
msgstr ""
-#: rpm.c:314
+#: rpm.c:313
msgid " --eval '<name>+' "
msgstr ""
-#: rpm.c:315
+#: rpm.c:314
msgid "print the expansion of macro <name> to stdout"
msgstr ""
-#: rpm.c:316
+#: rpm.c:315
msgid " --pipe <cmd> "
msgstr ""
-#: rpm.c:317 rpmqv.c:142 rpmqv.c:455
+#: rpm.c:316 rpmqv.c:141 rpmqv.c:454
msgid "send stdout to <cmd>"
msgstr ""
-#: rpm.c:318
+#: rpm.c:317
msgid " --rcfile <file> "
msgstr ""
-#: rpm.c:319
+#: rpm.c:318
msgid "use <file> instead of /etc/rpmrc and $HOME/.rpmrc"
msgstr ""
-#: rpm.c:321 rpmqv.c:160 rpmqv.c:459
+#: rpm.c:320 rpmqv.c:159 rpmqv.c:458
msgid "display final rpmrc and macro configuration"
msgstr ""
-#: rpm.c:323 rpmqv.c:467
+#: rpm.c:322 rpmqv.c:466
msgid "be a little more verbose"
msgstr ""
-#: rpm.c:325 rpmqv.c:469
+#: rpm.c:324 rpmqv.c:468
msgid "be incredibly verbose (for debugging)"
msgstr ""
-#: rpm.c:328
+#: rpm.c:327
msgid " Install, upgrade and query (with -p) allow URL's to be used in place"
msgstr ""
-#: rpm.c:329
+#: rpm.c:328
msgid " of file names as well as the following options:"
msgstr ""
-#: rpm.c:330
+#: rpm.c:329
msgid " --ftpproxy <host> "
msgstr ""
-#: rpm.c:331 rpmqv.c:476
+#: rpm.c:330 rpmqv.c:475
msgid "hostname or IP of ftp proxy"
msgstr ""
-#: rpm.c:332
+#: rpm.c:331
msgid " --ftpport <port> "
msgstr ""
-#: rpm.c:333 rpmqv.c:478
+#: rpm.c:332 rpmqv.c:477
msgid "port number of ftp server (or proxy)"
msgstr ""
-#: rpm.c:334
+#: rpm.c:333
msgid " --httpproxy <host> "
msgstr ""
-#: rpm.c:335 rpmqv.c:480
+#: rpm.c:334 rpmqv.c:479
msgid "hostname or IP of http proxy"
msgstr ""
-#: rpm.c:336
+#: rpm.c:335
msgid " --httpport <port> "
msgstr ""
-#: rpm.c:337 rpmqv.c:482
+#: rpm.c:336 rpmqv.c:481
msgid "port number of http server (or proxy)"
msgstr ""
-#: rpm.c:341 rpmqv.c:502
+#: rpm.c:340 rpmqv.c:501
msgid "query mode"
msgstr ""
-#: rpm.c:342 rpm.c:388 rpm.c:413 rpm.c:465 rpm.c:539
+#: rpm.c:341 rpm.c:387 rpm.c:412 rpm.c:464 rpm.c:538
msgid " --dbpath <dir> "
msgstr ""
-#: rpm.c:343 rpm.c:389 rpm.c:414 rpm.c:466 rpm.c:540 rpmqv.c:462
+#: rpm.c:342 rpm.c:388 rpm.c:413 rpm.c:465 rpm.c:539 rpmqv.c:461
msgid "use <dir> as the directory for the database"
msgstr ""
-#: rpm.c:344
+#: rpm.c:343
msgid " --queryformat <qfmt>"
msgstr ""
-#: rpm.c:345 rpmqv.c:504
+#: rpm.c:344 rpmqv.c:503
msgid "use <qfmt> as the header format (implies --info)"
msgstr ""
-#: rpm.c:346 rpm.c:390 rpm.c:448 rpm.c:477
+#: rpm.c:345 rpm.c:389 rpm.c:447 rpm.c:476
msgid " --root <dir> "
msgstr ""
-#: rpm.c:347 rpm.c:391 rpm.c:449 rpm.c:478 rpm.c:542 rpmqv.c:145 rpmqv.c:464
+#: rpm.c:346 rpm.c:390 rpm.c:448 rpm.c:477 rpm.c:541 rpmqv.c:144 rpmqv.c:463
msgid "use <dir> as the top level directory"
msgstr ""
-#: rpm.c:348
+#: rpm.c:347
msgid " Package specification options:"
msgstr ""
-#: rpm.c:350
+#: rpm.c:349
msgid "query all packages"
msgstr ""
-#: rpm.c:351
+#: rpm.c:350
msgid " -f <file>+ "
msgstr ""
-#: rpm.c:352
+#: rpm.c:351
msgid "query package owning <file>"
msgstr ""
-#: rpm.c:353
+#: rpm.c:352
msgid " -p <packagefile>+ "
msgstr ""
-#: rpm.c:354
+#: rpm.c:353
msgid "query (uninstalled) package <packagefile>"
msgstr ""
-#: rpm.c:355
+#: rpm.c:354
msgid " --triggeredby <pkg>"
msgstr ""
-#: rpm.c:356
+#: rpm.c:355
msgid "query packages triggered by <pkg>"
msgstr ""
-#: rpm.c:357
+#: rpm.c:356
msgid " --whatprovides <cap>"
msgstr ""
-#: rpm.c:358
+#: rpm.c:357
msgid "query packages which provide <cap> capability"
msgstr ""
-#: rpm.c:359
+#: rpm.c:358
msgid " --whatrequires <cap>"
msgstr ""
-#: rpm.c:360
+#: rpm.c:359
msgid "query packages which require <cap> capability"
msgstr ""
-#: rpm.c:361
+#: rpm.c:360
msgid " Information selection options:"
msgstr ""
-#: rpm.c:363 rpmqv.c:508
+#: rpm.c:362 rpmqv.c:507
msgid "display package information"
msgstr ""
-#: rpm.c:365 rpmqv.c:510
+#: rpm.c:364 rpmqv.c:509
msgid "display the package's change log"
msgstr ""
-#: rpm.c:367 rpmqv.c:512
+#: rpm.c:366 rpmqv.c:511
msgid "display package file list"
msgstr ""
-#: rpm.c:369 rpmqv.c:514
+#: rpm.c:368 rpmqv.c:513
msgid "show file states (implies -l)"
msgstr ""
-#: rpm.c:371 rpmqv.c:516
+#: rpm.c:370 rpmqv.c:515
msgid "list only documentation files (implies -l)"
msgstr ""
-#: rpm.c:373 rpmqv.c:518
+#: rpm.c:372 rpmqv.c:517
msgid "list only configuration files (implies -l)"
msgstr ""
-#: rpm.c:375 rpmqv.c:520
+#: rpm.c:374 rpmqv.c:519
msgid ""
"show all verifiable information for each file (must be used with -l, -c, or "
"-d)"
msgstr ""
-#: rpm.c:377
+#: rpm.c:376
msgid "list capabilities package provides"
msgstr ""
-#: rpm.c:379
+#: rpm.c:378
msgid "list package dependencies"
msgstr ""
-#: rpm.c:381
+#: rpm.c:380
msgid "print the various [un]install scripts"
msgstr ""
-#: rpm.c:383
+#: rpm.c:382
msgid "show the trigger scripts contained in the package"
msgstr ""
-#: rpm.c:387 rpmqv.c:531
+#: rpm.c:386 rpmqv.c:530
msgid ""
"verify a package installation using the same same package specification "
"options as -q"
msgstr ""
-#: lib/poptBT.c:183 lib/verify.c:56 rpm.c:393 rpm.c:435 rpm.c:470 rpmqv.c:263
-#: rpmqv.c:533 rpmqv.c:581 rpmqv.c:615
+#: lib/poptBT.c:183 lib/verify.c:54 rpm.c:392 rpm.c:434 rpm.c:469 rpmqv.c:262
+#: rpmqv.c:532 rpmqv.c:580 rpmqv.c:614
msgid "do not verify package dependencies"
msgstr ""
-#: lib/verify.c:62 rpm.c:395 rpmqv.c:209 rpmqv.c:537
+#: lib/verify.c:60 rpm.c:394 rpmqv.c:208 rpmqv.c:536
msgid "do not verify file md5 checksums"
msgstr ""
-#: rpm.c:397 rpmqv.c:535
+#: rpm.c:396 rpmqv.c:534
msgid "do not verify file attributes"
msgstr ""
-#: rpm.c:399 rpmqv.c:542
+#: rpm.c:398 rpmqv.c:541
msgid "list the tags that can be used in a query format"
msgstr ""
-#: rpm.c:402
+#: rpm.c:401
msgid " --install <packagefile>"
msgstr ""
-#: rpm.c:403
+#: rpm.c:402
msgid " -i <packagefile> "
msgstr ""
-#: rpm.c:404 rpmqv.c:259 rpmqv.c:556
+#: rpm.c:403 rpmqv.c:258 rpmqv.c:555
msgid "install package"
msgstr ""
-#: rpm.c:405
+#: rpm.c:404
msgid " --excludepath <path>"
msgstr ""
-#: rpm.c:406
+#: rpm.c:405
msgid "skip files in path <path>"
msgstr ""
-#: rpm.c:407
+#: rpm.c:406
msgid " --relocate <oldpath>=<newpath>"
msgstr ""
-#: rpm.c:408 rpmqv.c:593
+#: rpm.c:407 rpmqv.c:592
msgid "relocate files from <oldpath> to <newpath>"
msgstr ""
-#: rpm.c:410 rpmqv.c:231 rpmqv.c:561
+#: rpm.c:409 rpmqv.c:230 rpmqv.c:560
msgid "relocate files in non-relocateable package"
msgstr ""
-#: rpm.c:411
+#: rpm.c:410
msgid " --prefix <dir> "
msgstr ""
-#: rpm.c:412 rpmqv.c:277 rpmqv.c:591
+#: rpm.c:411 rpmqv.c:276 rpmqv.c:590
msgid "relocate the package to <dir>, if relocatable"
msgstr ""
-#: rpm.c:416 rpmqv.c:237 rpmqv.c:563
+#: rpm.c:415 rpmqv.c:236 rpmqv.c:562
msgid "do not install documentation"
msgstr ""
-#: rpm.c:418 rpmqv.c:242 rpmqv.c:567
+#: rpm.c:417 rpmqv.c:241 rpmqv.c:566
msgid "short hand for --replacepkgs --replacefiles"
msgstr ""
-#: rpm.c:420 rpmqv.c:248 rpmqv.c:569
+#: rpm.c:419 rpmqv.c:247 rpmqv.c:568
msgid "print hash marks as package installs (good with -v)"
msgstr ""
-#: rpm.c:422 rpmqv.c:225 rpmqv.c:558
+#: rpm.c:421 rpmqv.c:224 rpmqv.c:557
msgid "install all files, even configurations which might otherwise be skipped"
msgstr ""
-#: rpm.c:425 rpmqv.c:250 rpmqv.c:571
+#: rpm.c:424 rpmqv.c:249 rpmqv.c:570
msgid "don't verify package architecture"
msgstr ""
-#: rpm.c:427 rpmqv.c:255 rpmqv.c:573
+#: rpm.c:426 rpmqv.c:254 rpmqv.c:572
msgid "don't check disk space before installing"
msgstr ""
-#: rpm.c:429 rpmqv.c:252 rpmqv.c:575
+#: rpm.c:428 rpmqv.c:251 rpmqv.c:574
msgid "don't verify package operating system"
msgstr ""
-#: rpm.c:431 rpmqv.c:257 rpmqv.c:577
+#: rpm.c:430 rpmqv.c:256 rpmqv.c:576
msgid "install documentation"
msgstr ""
-#: rpm.c:433 rpm.c:468 rpmqv.c:261 rpmqv.c:579 rpmqv.c:613
+#: rpm.c:432 rpm.c:467 rpmqv.c:260 rpmqv.c:578 rpmqv.c:612
msgid "update the database, but do not modify the filesystem"
msgstr ""
-#: rpm.c:437 rpm.c:472 rpmqv.c:265 rpmqv.c:583 rpmqv.c:617
+#: rpm.c:436 rpm.c:471 rpmqv.c:264 rpmqv.c:582 rpmqv.c:616
msgid "do not reorder package installation to satisfy dependencies"
msgstr ""
-#: rpm.c:439
+#: rpm.c:438
msgid "don't execute any installation scripts"
msgstr ""
-#: rpm.c:441 rpm.c:476 rpmqv.c:621
+#: rpm.c:440 rpm.c:475 rpmqv.c:620
msgid "don't execute any scripts triggered by this package"
msgstr ""
-#: rpm.c:443 rpmqv.c:275 rpmqv.c:589
+#: rpm.c:442 rpmqv.c:274 rpmqv.c:588
msgid "print percentages as package installs"
msgstr ""
-#: rpm.c:445 rpmqv.c:286 rpmqv.c:595
+#: rpm.c:444 rpmqv.c:285 rpmqv.c:594
msgid "install even if the package replaces installed files"
msgstr ""
-#: rpm.c:447 rpmqv.c:288 rpmqv.c:597
+#: rpm.c:446 rpmqv.c:287 rpmqv.c:596
msgid "reinstall if the package is already present"
msgstr ""
-#: rpm.c:451 rpmqv.c:290 rpmqv.c:599
+#: rpm.c:450 rpmqv.c:289 rpmqv.c:598
msgid "don't install, but tell if it would work or not"
msgstr ""
-#: rpm.c:454
+#: rpm.c:453
msgid " --upgrade <packagefile>"
msgstr ""
-#: rpm.c:455
+#: rpm.c:454
msgid " -U <packagefile> "
msgstr ""
-#: rpm.c:456 rpmqv.c:603
+#: rpm.c:455 rpmqv.c:602
msgid "upgrade package (same options as --install, plus)"
msgstr ""
-#: rpm.c:458 rpmqv.c:272 rpmqv.c:605
+#: rpm.c:457 rpmqv.c:271 rpmqv.c:604
msgid ""
"upgrade to an old version of the package (--force on upgrades does this "
"automatically)"
msgstr ""
-#: rpm.c:460
+#: rpm.c:459
msgid " --erase <package>"
msgstr ""
-#: rpm.c:462 rpmqv.c:235 rpmqv.c:609
+#: rpm.c:461 rpmqv.c:234 rpmqv.c:608
msgid "erase (uninstall) package"
msgstr ""
-#: rpm.c:464 rpmqv.c:228 rpmqv.c:611
+#: rpm.c:463 rpmqv.c:227 rpmqv.c:610
msgid ""
"remove all packages which match <package> (normally an error is generated if "
"<package> specified multiple packages)"
msgstr ""
-#: rpm.c:474 rpmqv.c:619
+#: rpm.c:473 rpmqv.c:618
msgid "do not execute any package specific scripts"
msgstr ""
-#: rpm.c:480
+#: rpm.c:479
msgid " -b<stage> <spec> "
msgstr ""
-#: rpm.c:481
+#: rpm.c:480
msgid " -t<stage> <tarball> "
msgstr ""
-#: rpm.c:482
+#: rpm.c:481
msgid "build package, where <stage> is one of:"
msgstr ""
-#: rpm.c:484
+#: rpm.c:483
msgid "prep (unpack sources and apply patches)"
msgstr ""
-#: rpm.c:486
+#: rpm.c:485
#, c-format
msgid "list check (do some cursory checks on %files)"
msgstr ""
-#: rpm.c:488
+#: rpm.c:487
msgid "compile (prep and compile)"
msgstr ""
-#: rpm.c:490
+#: rpm.c:489
msgid "install (prep, compile, install)"
msgstr ""
-#: rpm.c:492
+#: rpm.c:491
msgid "binary package (prep, compile, install, package)"
msgstr ""
-#: rpm.c:494
+#: rpm.c:493
msgid "bin/src package (prep, compile, install, package)"
msgstr ""
-#: lib/poptBT.c:194 rpm.c:496
+#: lib/poptBT.c:194 rpm.c:495
msgid "skip straight to specified stage (only for c,i)"
msgstr ""
-#: lib/poptBT.c:173 rpm.c:498
+#: lib/poptBT.c:173 rpm.c:497
msgid "remove build tree when done"
msgstr ""
-#: lib/poptBT.c:190 rpm.c:500
+#: lib/poptBT.c:190 rpm.c:499
msgid "remove sources when done"
msgstr ""
-#: rpm.c:502
+#: rpm.c:501
msgid "remove spec file when done"
msgstr ""
-#: lib/poptBT.c:196 rpm.c:504 rpmqv.c:201
+#: lib/poptBT.c:196 rpm.c:503 rpmqv.c:200
msgid "generate PGP/GPG signature"
msgstr ""
-#: rpm.c:505
+#: rpm.c:504
msgid " --buildroot <dir> "
msgstr ""
-#: rpm.c:506
+#: rpm.c:505
msgid "use <dir> as the build root"
msgstr ""
-#: rpm.c:507
+#: rpm.c:506
msgid " --target=<platform>+"
msgstr ""
-#: rpm.c:508
+#: rpm.c:507
msgid "build the packages for the build targets platform1...platformN."
msgstr ""
-#: rpm.c:510
+#: rpm.c:509
msgid "do not execute any stages"
msgstr ""
-#: rpm.c:511
+#: rpm.c:510
msgid " --timecheck <secs> "
msgstr ""
-#: rpm.c:512
+#: rpm.c:511
msgid "set the time check to <secs> seconds (0 disables)"
msgstr ""
-#: rpm.c:514
+#: rpm.c:513
msgid " --rebuild <src_pkg> "
msgstr ""
-#: rpm.c:515
+#: rpm.c:514
msgid ""
"install source package, build binary package and remove spec file, sources, "
"patches, and icons."
msgstr ""
-#: rpm.c:516
+#: rpm.c:515
msgid " --recompile <src_pkg> "
msgstr ""
-#: rpm.c:517
+#: rpm.c:516
msgid "like --rebuild, but don't build any package"
msgstr ""
-#: rpm.c:520
+#: rpm.c:519
msgid " --resign <pkg>+ "
msgstr ""
-#: rpm.c:521 rpmqv.c:199 rpmqv.c:627
+#: rpm.c:520 rpmqv.c:198 rpmqv.c:626
msgid "sign a package (discard current signature)"
msgstr ""
-#: rpm.c:522
+#: rpm.c:521
msgid " --addsign <pkg>+ "
msgstr ""
-#: rpm.c:523 rpmqv.c:197 rpmqv.c:629
+#: rpm.c:522 rpmqv.c:196 rpmqv.c:628
msgid "add a signature to a package"
msgstr ""
-#: rpm.c:524
+#: rpm.c:523
msgid " --checksig <pkg>+"
msgstr ""
-#: rpm.c:525
+#: rpm.c:524
msgid " -K <pkg>+ "
msgstr ""
-#: rpm.c:526 rpmqv.c:203 rpmqv.c:633
+#: rpm.c:525 rpmqv.c:202 rpmqv.c:632
msgid "verify package signature"
msgstr ""
-#: rpm.c:528 rpmqv.c:205 rpmqv.c:635
+#: rpm.c:527 rpmqv.c:204 rpmqv.c:634
msgid "skip any PGP signatures"
msgstr ""
-#: rpm.c:530 rpmqv.c:207 rpmqv.c:637
+#: rpm.c:529 rpmqv.c:206 rpmqv.c:636
msgid "skip any GPG signatures"
msgstr ""
-#: rpm.c:532 rpmqv.c:639
+#: rpm.c:531 rpmqv.c:638
msgid "skip any MD5 signatures"
msgstr ""
-#: rpm.c:536
+#: rpm.c:535
msgid "make sure a valid database exists"
msgstr ""
-#: rpm.c:538
+#: rpm.c:537
msgid "rebuild database from existing database"
msgstr ""
-#: rpm.c:546 rpmqv.c:544
+#: rpm.c:545 rpmqv.c:543
msgid ""
"set the file permissions to those in the package database using the same "
"package specification options as -q"
msgstr ""
-#: rpm.c:549 rpmqv.c:547
+#: rpm.c:548 rpmqv.c:546
msgid ""
"set the file owner and group to those in the package database using the same "
"package specification options as -q"
msgstr ""
-#: rpm.c:689 rpm.c:695 rpm.c:704 rpm.c:726 rpm.c:732 rpm.c:739 rpm.c:747
-#: rpm.c:755 rpm.c:776 rpm.c:839 rpmqv.c:832 rpmqv.c:838 rpmqv.c:845
-#: rpmqv.c:851 rpmqv.c:885 rpmqv.c:893 rpmqv.c:899 rpmqv.c:907 rpmqv.c:974
+#: rpm.c:688 rpm.c:694 rpm.c:703 rpm.c:725 rpm.c:731 rpm.c:738 rpm.c:746
+#: rpm.c:754 rpm.c:775 rpm.c:838 rpmqv.c:831 rpmqv.c:837 rpmqv.c:844
+#: rpmqv.c:850 rpmqv.c:884 rpmqv.c:892 rpmqv.c:898 rpmqv.c:906 rpmqv.c:973
msgid "only one major mode may be specified"
msgstr ""
-#: rpm.c:697
+#: rpm.c:696
msgid "-u and --uninstall are deprecated and no longer work.\n"
msgstr ""
-#: rpm.c:699
+#: rpm.c:698
msgid "Use -e or --erase instead.\n"
msgstr ""
-#: rpm.c:782 rpmqv.c:869
+#: rpm.c:781 rpmqv.c:868
msgid "relocations must begin with a /"
msgstr ""
-#: rpm.c:784 rpmqv.c:871
+#: rpm.c:783 rpmqv.c:870
msgid "relocations must contain a ="
msgstr ""
-#: rpm.c:787 rpmqv.c:874
+#: rpm.c:786 rpmqv.c:873
msgid "relocations must have a / following the ="
msgstr ""
-#: rpm.c:796 rpmqv.c:858
+#: rpm.c:795 rpmqv.c:857
msgid "exclude paths must begin with a /"
msgstr ""
-#: rpm.c:805 rpmqv.c:928
+#: rpm.c:804 rpmqv.c:927
msgid "The --rcfile option has been eliminated.\n"
msgstr ""
-#: rpm.c:806
+#: rpm.c:805
msgid "Use --macros with a colon separated list of macro files to read.\n"
msgstr ""
-#: rpm.c:811 rpmqv.c:934
+#: rpm.c:810 rpmqv.c:933
#, c-format
msgid "Internal error in argument processing (%d) :-(\n"
msgstr ""
-#: rpm.c:846 rpmqv.c:989
+#: rpm.c:845 rpmqv.c:988
msgid "one type of query/verify may be performed at a time"
msgstr ""
-#: rpm.c:851 rpmqv.c:993
+#: rpm.c:850 rpmqv.c:992
msgid "unexpected query flags"
msgstr ""
-#: rpm.c:854 rpmqv.c:996
+#: rpm.c:853 rpmqv.c:995
msgid "unexpected query format"
msgstr ""
-#: rpm.c:857 rpmqv.c:999
+#: rpm.c:856 rpmqv.c:998
msgid "unexpected query source"
msgstr ""
-#: rpm.c:860 rpmqv.c:1009
+#: rpm.c:859 rpmqv.c:1008
msgid "only installation, upgrading, rmsource and rmspec may be forced"
msgstr ""
-#: rpm.c:863 rpmqv.c:1014
+#: rpm.c:862 rpmqv.c:1013
msgid "files may only be relocated during package installation"
msgstr ""
-#: rpm.c:866 rpmqv.c:1017
+#: rpm.c:865 rpmqv.c:1016
msgid "only one of --prefix or --relocate may be used"
msgstr ""
-#: rpm.c:869 rpmqv.c:1020
+#: rpm.c:868 rpmqv.c:1019
msgid ""
"--relocate and --excludepath may only be used when installing new packages"
msgstr ""
-#: rpm.c:872 rpmqv.c:1023
+#: rpm.c:871 rpmqv.c:1022
msgid "--prefix may only be used when installing new packages"
msgstr ""
-#: rpm.c:875 rpmqv.c:1026
+#: rpm.c:874 rpmqv.c:1025
msgid "arguments to --prefix must begin with a /"
msgstr ""
-#: rpm.c:878 rpmqv.c:1029
+#: rpm.c:877 rpmqv.c:1028
msgid "--hash (-h) may only be specified during package installation"
msgstr ""
-#: rpm.c:882 rpmqv.c:1033
+#: rpm.c:881 rpmqv.c:1032
msgid "--percent may only be specified during package installation"
msgstr ""
-#: rpm.c:886 rpmqv.c:1038
+#: rpm.c:885 rpmqv.c:1037
msgid "--replacefiles may only be specified during package installation"
msgstr ""
-#: rpm.c:890 rpmqv.c:1042
+#: rpm.c:889 rpmqv.c:1041
msgid "--replacepkgs may only be specified during package installation"
msgstr ""
-#: rpm.c:894 rpmqv.c:1046
+#: rpm.c:893 rpmqv.c:1045
msgid "--excludedocs may only be specified during package installation"
msgstr ""
-#: rpm.c:898 rpmqv.c:1050
+#: rpm.c:897 rpmqv.c:1049
msgid "--includedocs may only be specified during package installation"
msgstr ""
-#: rpm.c:902 rpmqv.c:1054
+#: rpm.c:901 rpmqv.c:1053
msgid "only one of --excludedocs and --includedocs may be specified"
msgstr ""
-#: rpm.c:906 rpmqv.c:1058
+#: rpm.c:905 rpmqv.c:1057
msgid "--ignorearch may only be specified during package installation"
msgstr ""
-#: rpm.c:910 rpmqv.c:1062
+#: rpm.c:909 rpmqv.c:1061
msgid "--ignoreos may only be specified during package installation"
msgstr ""
-#: rpm.c:914 rpmqv.c:1067
+#: rpm.c:913 rpmqv.c:1066
msgid "--ignoresize may only be specified during package installation"
msgstr ""
-#: rpm.c:918 rpmqv.c:1071
+#: rpm.c:917 rpmqv.c:1070
msgid "--allmatches may only be specified during package erasure"
msgstr ""
-#: rpm.c:922 rpmqv.c:1075
+#: rpm.c:921 rpmqv.c:1074
msgid "--allfiles may only be specified during package installation"
msgstr ""
-#: rpm.c:926 rpmqv.c:1080
+#: rpm.c:925 rpmqv.c:1079
msgid "--justdb may only be specified during package installation and erasure"
msgstr ""
-#: rpm.c:931
+#: rpm.c:930
msgid ""
"--noscripts may only be specified during package installation, erasure, and "
"verification"
msgstr ""
-#: rpm.c:935
+#: rpm.c:934
msgid ""
"--notriggers may only be specified during package installation, erasure, and "
"verification"
msgstr ""
-#: rpm.c:939 rpmqv.c:1091
+#: rpm.c:938 rpmqv.c:1090
msgid ""
"--nodeps may only be specified during package building, rebuilding, "
"recompilation, installation,erasure, and verification"
msgstr ""
-#: rpm.c:944 rpmqv.c:1096
+#: rpm.c:943 rpmqv.c:1095
msgid ""
"--test may only be specified during package installation, erasure, and "
"building"
msgstr ""
-#: rpm.c:948 rpmqv.c:1101
+#: rpm.c:947 rpmqv.c:1100
msgid ""
"--root (-r) may only be specified during installation, erasure, querying, "
"and database rebuilds"
msgstr ""
-#: rpm.c:960 rpmqv.c:1113
+#: rpm.c:959 rpmqv.c:1112
msgid "arguments to --root (-r) must begin with a /"
msgstr ""
-#: rpm.c:966
+#: rpm.c:965
msgid "--oldpackage may only be used during upgrades"
msgstr ""
-#: rpm.c:969 rpmqv.c:1120
+#: rpm.c:968 rpmqv.c:1119
msgid "--nopgp may only be used during signature checking"
msgstr ""
-#: rpm.c:972 rpmqv.c:1123
+#: rpm.c:971 rpmqv.c:1122
msgid "--nogpg may only be used during signature checking"
msgstr ""
-#: rpm.c:975 rpmqv.c:1128
+#: rpm.c:974 rpmqv.c:1127
msgid ""
"--nomd5 may only be used during signature checking and package verification"
msgstr ""
-#: rpm.c:986 rpmqv.c:1144
+#: rpm.c:985 rpmqv.c:1143
msgid "no files to sign\n"
msgstr ""
-#: rpm.c:991 rpmqv.c:1149
+#: rpm.c:990 rpmqv.c:1148
#, c-format
msgid "cannot access file %s\n"
msgstr ""
-#: rpm.c:1006 rpmqv.c:1165
+#: rpm.c:1005 rpmqv.c:1164
msgid "pgp not found: "
msgstr ""
-#: rpm.c:1010 rpmqv.c:1169
+#: rpm.c:1009 rpmqv.c:1168
msgid "Enter pass phrase: "
msgstr ""
-#: rpm.c:1012 rpmqv.c:1171
+#: rpm.c:1011 rpmqv.c:1170
msgid "Pass phrase check failed\n"
msgstr ""
-#: rpm.c:1015 rpmqv.c:1174
+#: rpm.c:1014 rpmqv.c:1173
msgid "Pass phrase is good.\n"
msgstr ""
-#: rpm.c:1020 rpmqv.c:1179
+#: rpm.c:1019 rpmqv.c:1178
msgid "Invalid %%_signature spec in macro file.\n"
msgstr ""
-#: rpm.c:1026 rpmqv.c:1185
+#: rpm.c:1025 rpmqv.c:1184
msgid "--sign may only be used during package building"
msgstr ""
-#: rpm.c:1041 rpmqv.c:1201
+#: rpm.c:1040 rpmqv.c:1200
msgid "exec failed\n"
msgstr ""
-#: rpm.c:1060 rpmqv.c:1445
+#: rpm.c:1059 rpmqv.c:1444
msgid "unexpected arguments to --querytags "
msgstr ""
-#: rpm.c:1071 rpmqv.c:1467
+#: rpm.c:1070 rpmqv.c:1466
msgid "no packages given for signature check"
msgstr ""
-#: rpm.c:1082 rpmqv.c:1478
+#: rpm.c:1081 rpmqv.c:1477
msgid "no packages given for signing"
msgstr ""
-#: rpm.c:1098 rpmqv.c:1341
+#: rpm.c:1097 rpmqv.c:1340
msgid "no packages given for uninstall"
msgstr ""
-#: rpm.c:1162 rpmqv.c:1370
+#: rpm.c:1161 rpmqv.c:1369
msgid "no packages given for install"
msgstr ""
-#: rpm.c:1186 rpmqv.c:1411
+#: rpm.c:1185 rpmqv.c:1410
msgid "extra arguments given for query of all packages"
msgstr ""
-#: rpm.c:1191 rpmqv.c:1416
+#: rpm.c:1190 rpmqv.c:1415
msgid "no arguments given for query"
msgstr ""
-#: rpm.c:1208 rpmqv.c:1433
+#: rpm.c:1207 rpmqv.c:1432
msgid "extra arguments given for verify of all packages"
msgstr ""
-#: rpm.c:1212 rpmqv.c:1437
+#: rpm.c:1211 rpmqv.c:1436
msgid "no arguments given for verify"
msgstr ""
msgid "cannot re-open payload: %s\n"
msgstr ""
-#: rpmqv.c:132
+#: rpmqv.c:131
msgid "provide less detailed output"
msgstr ""
-#: rpmqv.c:134
+#: rpmqv.c:133
msgid "provide more detailed output"
msgstr ""
-#: rpmqv.c:137
+#: rpmqv.c:136
msgid "'<name> <body>'"
msgstr ""
-#: rpmqv.c:139
+#: rpmqv.c:138
msgid "print macro expansion of <expr>+"
msgstr ""
-#: rpmqv.c:140
+#: rpmqv.c:139
msgid "<expr>+"
msgstr ""
-#: rpmqv.c:143
+#: rpmqv.c:142
msgid "<cmd>"
msgstr ""
-#: rpmqv.c:146 rpmqv.c:278
+#: rpmqv.c:145 rpmqv.c:277
msgid "<dir>"
msgstr ""
-#: rpmqv.c:148
+#: rpmqv.c:147
msgid "read <file:...> instead of default macro file(s)"
msgstr ""
-#: rpmqv.c:149 rpmqv.c:153 rpmqv.c:157
+#: rpmqv.c:148 rpmqv.c:152 rpmqv.c:156
msgid "<file:...>"
msgstr ""
-#: rpmqv.c:152 rpmqv.c:156
+#: rpmqv.c:151 rpmqv.c:155
msgid "read <file:...> instead of default rpmrc file(s)"
msgstr ""
-#: rpmqv.c:165
+#: rpmqv.c:164
msgid "disable use of libio(3) API"
msgstr ""
-#: rpmqv.c:168
+#: rpmqv.c:167
msgid "debug protocol data stream"
msgstr ""
-#: rpmqv.c:170
+#: rpmqv.c:169
msgid "debug rpmio I/O"
msgstr ""
-#: rpmqv.c:172
+#: rpmqv.c:171
msgid "debug URL cache handling"
msgstr ""
-#: rpmqv.c:180
+#: rpmqv.c:179
msgid "initialize database"
msgstr ""
-#: rpmqv.c:182
+#: rpmqv.c:181
msgid "rebuild database inverted lists from installed package headers"
msgstr ""
-#: rpmqv.c:185
+#: rpmqv.c:184
msgid "generate headers compatible with (legacy) rpm[23] packaging"
msgstr ""
-#: lib/poptBT.c:175 rpmqv.c:188
+#: lib/poptBT.c:175 rpmqv.c:187
msgid "generate headers compatible with rpm4 packaging"
msgstr ""
-#: rpmqv.c:233
+#: rpmqv.c:232
msgid "save erased package files by renaming into sub-directory"
msgstr ""
-#: rpmqv.c:235
+#: rpmqv.c:234
msgid "<package>+"
msgstr ""
-#: rpmqv.c:239 rpmqv.c:565
+#: rpmqv.c:238 rpmqv.c:564
msgid "skip files with leading component <path> "
msgstr ""
-#: rpmqv.c:240
+#: rpmqv.c:239
msgid "<path>"
msgstr ""
-#: rpmqv.c:245
+#: rpmqv.c:244
msgid "upgrade package(s) if already installed"
msgstr ""
-#: rpmqv.c:246 rpmqv.c:259 rpmqv.c:293
+#: rpmqv.c:245 rpmqv.c:258 rpmqv.c:292
msgid "<packagefile>+"
msgstr ""
-#: rpmqv.c:268 rpmqv.c:539
+#: rpmqv.c:267 rpmqv.c:538
msgid "do not execute scripts (if any)"
msgstr ""
-#: rpmqv.c:270 rpmqv.c:587
+#: rpmqv.c:269 rpmqv.c:586
msgid "don't execute any scriptlets triggered by this package"
msgstr ""
-#: rpmqv.c:280
+#: rpmqv.c:279
msgid "relocate files from path <old> to <new>"
msgstr ""
-#: rpmqv.c:281
+#: rpmqv.c:280
msgid "<old>=<new>"
msgstr ""
-#: rpmqv.c:283
+#: rpmqv.c:282
msgid "save erased package files by repackaging"
msgstr ""
-#: rpmqv.c:292
+#: rpmqv.c:291
msgid "upgrade package(s)"
msgstr ""
-#: rpmqv.c:312
+#: rpmqv.c:311
msgid "Query options (with -q or --query):"
msgstr ""
-#: rpmqv.c:315
+#: rpmqv.c:314
msgid "Verify options (with -V or --verify):"
msgstr ""
-#: rpmqv.c:321
+#: rpmqv.c:320
msgid "Signature options:"
msgstr ""
-#: rpmqv.c:327
+#: rpmqv.c:326
msgid "Database options:"
msgstr ""
-#: rpmqv.c:333
+#: rpmqv.c:332
msgid "Build options with [ <specfile> | <tarball> | <source package> ]:"
msgstr ""
-#: rpmqv.c:339
+#: rpmqv.c:338
msgid "Install/Upgrade/Erase options:"
msgstr ""
-#: rpmqv.c:344
+#: rpmqv.c:343
msgid "Common options for all rpm modes:"
msgstr ""
-#: rpmqv.c:378
+#: rpmqv.c:377
#, c-format
msgid "Usage: %s {--help}\n"
msgstr ""
-#: rpmqv.c:449
+#: rpmqv.c:448
msgid " All modes support the following options:"
msgstr ""
-#: rpmqv.c:450
+#: rpmqv.c:449
msgid " --define '<name> <body>'"
msgstr ""
-#: rpmqv.c:452
+#: rpmqv.c:451
msgid " --eval '<expr>+' "
msgstr ""
-#: rpmqv.c:453
+#: rpmqv.c:452
msgid "print the expansion of macro <expr> to stdout"
msgstr ""
-#: rpmqv.c:454
+#: rpmqv.c:453
msgid " --pipe <cmd> "
msgstr ""
-#: rpmqv.c:456
+#: rpmqv.c:455
msgid " --rcfile <file:...> "
msgstr ""
-#: rpmqv.c:457
+#: rpmqv.c:456
msgid "use <file:...> instead of default list of macro files"
msgstr ""
-#: rpmqv.c:461
+#: rpmqv.c:460
msgid " --dbpath <dir> "
msgstr ""
-#: rpmqv.c:463
+#: rpmqv.c:462
msgid " --root <dir> "
msgstr ""
-#: rpmqv.c:473
+#: rpmqv.c:472
msgid ""
" Install, upgrade and query (with -p) modes allow URL's to be used in place"
msgstr ""
-#: rpmqv.c:474
+#: rpmqv.c:473
msgid " of file names as well as the following options:"
msgstr ""
-#: rpmqv.c:475
+#: rpmqv.c:474
msgid " --ftpproxy <host> "
msgstr ""
-#: rpmqv.c:477
+#: rpmqv.c:476
msgid " --ftpport <port> "
msgstr ""
-#: rpmqv.c:479
+#: rpmqv.c:478
msgid " --httpproxy <host> "
msgstr ""
-#: rpmqv.c:481
+#: rpmqv.c:480
msgid " --httpport <port> "
msgstr ""
-#: rpmqv.c:487
+#: rpmqv.c:486
msgid " Package specification options:"
msgstr ""
-#: lib/poptQV.c:68 rpmqv.c:489
+#: lib/poptQV.c:68 rpmqv.c:488
msgid "query/verify all packages"
msgstr ""
-#: rpmqv.c:490
+#: rpmqv.c:489
msgid " -f <file>+ "
msgstr ""
-#: rpmqv.c:491
+#: rpmqv.c:490
msgid "query/verify package owning <file>"
msgstr ""
-#: rpmqv.c:492
+#: rpmqv.c:491
msgid " -p <packagefile>+ "
msgstr ""
-#: rpmqv.c:493
+#: rpmqv.c:492
msgid "query/verify (uninstalled) package <packagefile>"
msgstr ""
-#: rpmqv.c:494
+#: rpmqv.c:493
msgid " --triggeredby <pkg> "
msgstr ""
-#: rpmqv.c:495
+#: rpmqv.c:494
msgid "query/verify packages triggered by <pkg>"
msgstr ""
-#: rpmqv.c:496
+#: rpmqv.c:495
msgid " --whatprovides <cap> "
msgstr ""
-#: rpmqv.c:497
+#: rpmqv.c:496
msgid "query/verify packages which provide <cap> capability"
msgstr ""
-#: rpmqv.c:498
+#: rpmqv.c:497
msgid " --whatrequires <cap> "
msgstr ""
-#: rpmqv.c:499
+#: rpmqv.c:498
msgid "query/verify packages which require <cap> capability"
msgstr ""
-#: rpmqv.c:503
+#: rpmqv.c:502
msgid " --queryformat <qfmt> "
msgstr ""
-#: rpmqv.c:506
+#: rpmqv.c:505
msgid " Information selection options:"
msgstr ""
-#: rpmqv.c:522
+#: rpmqv.c:521
msgid "list capabilities provided by package"
msgstr ""
-#: rpmqv.c:524
+#: rpmqv.c:523
msgid "list capabilities required by package"
msgstr ""
-#: rpmqv.c:526
+#: rpmqv.c:525
msgid "print the various [un]install scriptlets"
msgstr ""
-#: rpmqv.c:528
+#: rpmqv.c:527
msgid "show the trigger scriptlets contained in the package"
msgstr ""
-#: rpmqv.c:554
+#: rpmqv.c:553
msgid " --install <packagefile>"
msgstr ""
-#: rpmqv.c:555
+#: rpmqv.c:554
msgid " -i <packagefile> "
msgstr ""
-#: rpmqv.c:564
+#: rpmqv.c:563
msgid " --excludepath <path> "
msgstr ""
-#: rpmqv.c:585
+#: rpmqv.c:584
msgid "don't execute any installation scriptlets"
msgstr ""
-#: rpmqv.c:590
+#: rpmqv.c:589
msgid " --prefix <dir> "
msgstr ""
-#: rpmqv.c:592
+#: rpmqv.c:591
msgid " --relocate <oldpath>=<newpath>"
msgstr ""
-#: rpmqv.c:601
+#: rpmqv.c:600
msgid " --upgrade <packagefile>"
msgstr ""
-#: rpmqv.c:602
+#: rpmqv.c:601
msgid " -U <packagefile> "
msgstr ""
-#: rpmqv.c:607
+#: rpmqv.c:606
msgid " --erase <package>"
msgstr ""
-#: rpmqv.c:626
+#: rpmqv.c:625
msgid " --resign <pkg>+ "
msgstr ""
-#: rpmqv.c:628
+#: rpmqv.c:627
msgid " --addsign <pkg>+ "
msgstr ""
-#: rpmqv.c:631
+#: rpmqv.c:630
msgid " --checksig <pkg>+"
msgstr ""
-#: rpmqv.c:632
+#: rpmqv.c:631
msgid " -K <pkg>+ "
msgstr ""
-#: rpmqv.c:645
+#: rpmqv.c:644
msgid "initalize database (unnecessary, legacy use)"
msgstr ""
-#: rpmqv.c:647
+#: rpmqv.c:646
msgid "rebuild database indices from existing database headers"
msgstr ""
-#: rpmqv.c:929
+#: rpmqv.c:928
msgid "Use \"--macros <file:...>\" instead.\n"
msgstr ""
-#: rpmqv.c:1003
+#: rpmqv.c:1002
msgid "--dbpath given for operation that does not use a database"
msgstr ""
-#: rpmqv.c:1087
+#: rpmqv.c:1086
msgid ""
"--notriggers may only be specified during package installation and erasure"
msgstr ""
-#: rpmqv.c:1241
+#: rpmqv.c:1240
msgid "no packages files given for rebuild"
msgstr ""
-#: rpmqv.c:1310
+#: rpmqv.c:1309
msgid "no spec files given for build"
msgstr ""
-#: rpmqv.c:1312
+#: rpmqv.c:1311
msgid "no tar files given for build"
msgstr ""
msgid "line %d: Bad %s number: %s\n"
msgstr ""
-#: lib/cpio.c:284
-msgid "========= Directories not explictly included in package:\n"
-msgstr ""
-
-#: lib/cpio.c:286
-#, c-format
-msgid "%9d %s\n"
-msgstr ""
-
-#: lib/cpio.c:1397
-#, c-format
-msgid "%s directory created with perms %04o.\n"
-msgstr ""
-
-#: lib/cpio.c:1499 lib/cpio.c:1615
-#, c-format
-msgid "%s saved as %s\n"
-msgstr ""
-
-#: lib/cpio.c:1640
-#, c-format
-msgid "%s rmdir of %s failed: Directory not empty\n"
-msgstr ""
-
-#: lib/cpio.c:1645
-#, c-format
-msgid "%s rmdir of %s failed: %s\n"
-msgstr ""
-
-#: lib/cpio.c:1654
-#, c-format
-msgid "%s unlink of %s failed: %s\n"
-msgstr ""
-
-#: lib/cpio.c:1671
-#, c-format
-msgid "%s created as %s\n"
-msgstr ""
-
-#: lib/cpio.c:2072
+#: lib/cpio.c:195
#, c-format
msgid "(error 0x%x)"
msgstr ""
-#: lib/cpio.c:2075
+#: lib/cpio.c:198
msgid "Bad magic"
msgstr ""
-#: lib/cpio.c:2076
+#: lib/cpio.c:199
msgid "Bad/unreadable header"
msgstr ""
-#: lib/cpio.c:2097
+#: lib/cpio.c:220
msgid "Header size too big"
msgstr ""
-#: lib/cpio.c:2098
+#: lib/cpio.c:221
msgid "Unknown file type"
msgstr ""
-#: lib/cpio.c:2099
+#: lib/cpio.c:222
msgid "Missing hard link"
msgstr ""
-#: lib/cpio.c:2100
+#: lib/cpio.c:223
msgid "MD5 sum mismatch"
msgstr ""
-#: lib/cpio.c:2101
+#: lib/cpio.c:224
msgid "Internal error"
msgstr ""
-#: lib/cpio.c:2110
+#: lib/cpio.c:233
msgid " failed - "
msgstr ""
msgid "file %s is on an unknown device\n"
msgstr ""
+#: lib/fsm.c:214
+msgid "========= Directories not explictly included in package:\n"
+msgstr ""
+
+#: lib/fsm.c:216
+#, c-format
+msgid "%9d %s\n"
+msgstr ""
+
+#: lib/fsm.c:1177
+#, c-format
+msgid "%s directory created with perms %04o.\n"
+msgstr ""
+
+#: lib/fsm.c:1279 lib/fsm.c:1395
+#, c-format
+msgid "%s saved as %s\n"
+msgstr ""
+
+#: lib/fsm.c:1420
+#, c-format
+msgid "%s rmdir of %s failed: Directory not empty\n"
+msgstr ""
+
+#: lib/fsm.c:1425
+#, c-format
+msgid "%s rmdir of %s failed: %s\n"
+msgstr ""
+
+#: lib/fsm.c:1434
+#, c-format
+msgid "%s unlink of %s failed: %s\n"
+msgstr ""
+
+#: lib/fsm.c:1451
+#, c-format
+msgid "%s created as %s\n"
+msgstr ""
+
#. This should not be allowed
#: lib/header.c:172
msgid "dataLength() RPM_STRING_TYPE count must be 1.\n"
msgstr ""
-#: lib/header.c:207 lib/header.c:1036 lib/install.c:236
+#: lib/header.c:207 lib/header.c:1036 lib/psm.c:500
#, c-format
msgid "Data type %d not supported\n"
msgstr ""
msgid "(unknown type)"
msgstr ""
-#: lib/install.c:80
-#, c-format
-msgid "user %s does not exist - using root\n"
-msgstr ""
-
-#: lib/install.c:88
-#, c-format
-msgid "group %s does not exist - using root\n"
-msgstr ""
-
-#.
-#. * This would probably be a good place to check if disk space
-#. * was used up - if so, we should return a different error.
-#.
-#. XXX FIXME: Fclose with libio destroys errno
-#: lib/install.c:461
-#, c-format
-msgid "unpacking of archive failed%s%s: %s\n"
-msgstr ""
-
-#: lib/install.c:462
-msgid " on file "
-msgstr ""
-
-#: lib/install.c:503
-#, c-format
-msgid "cannot create %s %s\n"
-msgstr ""
-
-#: lib/install.c:509
-#, c-format
-msgid "cannot write to %s\n"
-msgstr ""
-
-#: lib/install.c:530
-msgid "installing a source package\n"
-msgstr ""
-
-#: lib/install.c:582
-msgid "source package contains no .spec file\n"
-msgstr ""
-
-#: lib/install.c:662
-msgid "source package expected, binary found\n"
-msgstr ""
-
-#: lib/install.c:733 lib/uninstall.c:26
-#, c-format
-msgid "%s: %s-%s-%s has %d files, test = %d\n"
-msgstr ""
-
-#: lib/install.c:797 lib/install.c:879 lib/uninstall.c:69 lib/uninstall.c:91
-#, c-format
-msgid "%s: running %s script(s) (if any)\n"
-msgstr ""
-
-#: lib/install.c:804
-msgid "skipping %s-%s-%s install, %%pre scriptlet failed rc %d\n"
-msgstr ""
-
#: lib/misc.c:328 lib/misc.c:333 lib/misc.c:339
#, c-format
msgid "error creating temporary file %s\n"
msgid "unknown error %d encountered while manipulating package %s"
msgstr ""
+#: lib/psm.c:344
+#, c-format
+msgid "user %s does not exist - using root\n"
+msgstr ""
+
+#: lib/psm.c:352
+#, c-format
+msgid "group %s does not exist - using root\n"
+msgstr ""
+
+#.
+#. * This would probably be a good place to check if disk space
+#. * was used up - if so, we should return a different error.
+#.
+#. XXX FIXME: Fclose with libio destroys errno
+#: lib/psm.c:725
+#, c-format
+msgid "unpacking of archive failed%s%s: %s\n"
+msgstr ""
+
+#: lib/psm.c:726
+msgid " on file "
+msgstr ""
+
+#: lib/psm.c:767
+#, c-format
+msgid "cannot create %s %s\n"
+msgstr ""
+
+#: lib/psm.c:773
+#, c-format
+msgid "cannot write to %s\n"
+msgstr ""
+
+#: lib/psm.c:794
+msgid "installing a source package\n"
+msgstr ""
+
+#: lib/psm.c:846
+msgid "source package contains no .spec file\n"
+msgstr ""
+
+#: lib/psm.c:926
+msgid "source package expected, binary found\n"
+msgstr ""
+
+#: lib/psm.c:997 lib/psm.c:1188
+#, c-format
+msgid "%s: %s-%s-%s has %d files, test = %d\n"
+msgstr ""
+
+#: lib/psm.c:1061 lib/psm.c:1143 lib/psm.c:1231 lib/psm.c:1253
+#, c-format
+msgid "%s: running %s script(s) (if any)\n"
+msgstr ""
+
+#: lib/psm.c:1068
+msgid "skipping %s-%s-%s install, %%pre scriptlet failed rc %d\n"
+msgstr ""
+
#: lib/query.c:151
#, c-format
msgid "incorrect format: %s\n"
msgid "%s skipped due to missingok flag\n"
msgstr ""
-#: lib/verify.c:59
+#: lib/verify.c:57
msgid "don't verify files in package"
msgstr ""
-#: lib/verify.c:65
+#: lib/verify.c:63
msgid "do not execute %verifyscript (if any)"
msgstr ""
-#: lib/verify.c:241
+#: lib/verify.c:239
msgid "package lacks both user name and id lists (this should never happen)\n"
msgstr ""
-#: lib/verify.c:259
+#: lib/verify.c:257
msgid "package lacks both group name and id lists (this should never happen)\n"
msgstr ""
-#: lib/verify.c:321
+#: lib/verify.c:319
#, c-format
msgid "missing %s"
msgstr ""
-#: lib/verify.c:402
+#: lib/verify.c:400
#, c-format
msgid "Unsatisfied dependencies for %s-%s-%s: "
msgstr ""
#include <rpmurl.h>
#include "build.h"
-#include "install.h"
#include "signature.h"
#include "debug.h"
#endif
#ifdef IAM_RPMEIU
-#include "install.h"
#define GETOPT_INSTALL 1014
#define GETOPT_RELOCATE 1016
#define GETOPT_EXCLUDEPATH 1019