rpm  5.4.10
psm.c
Go to the documentation of this file.
1 
6 #include "system.h"
7 
8 #define _MIRE_INTERNAL /* XXX mireApply doesn't tell which pattern matched. */
9 
10 #include <rpmio_internal.h> /* XXX FDSTAT_READ */
11 #include <rpmcb.h> /* XXX fnpyKey */
12 #include <rpmsx.h>
13 #include <rpmmacro.h>
14 #include <rpmurl.h>
15 
16 #include <rpmaug.h>
17 #include <rpmficl.h>
18 #include <rpmjs.h>
19 #include <rpmlua.h>
20 #include <rpmperl.h>
21 #include <rpmpython.h>
22 #include <rpmruby.h>
23 #include <rpmsm.h>
24 #include <rpmsql.h>
25 #include <rpmsquirrel.h>
26 #include <rpmtcl.h>
27 
28 #if defined(WITH_LUA) || defined(WITH_AUGEAS) || defined(WITH_FICL) || defined(WITH_GPSEE) || defined(WITH_PERLEMBED) || defined(WITH_PYTHONEMBED) || defined(WITH_RUBYEMBED) || defined(WITH_SEMANAGE) || defined(WITH_SQLITE) || defined(WITH_SQUIRREL) || defined(WITH_TCL)
29 #define _WITH_EMBEDDED
30 #else
31 #undef _WITH_ENBEDDED
32 #endif
33 
34 #include <rpmtag.h>
35 #include <rpmtypes.h>
36 #include <pkgio.h>
37 #define _RPMDB_INTERNAL
38 #include <rpmdb.h> /* XXX for db_chrootDone */
39 #include <rpmtxn.h>
40 #include "signature.h" /* signature constants */
41 #include <rpmlib.h>
42 
43 #define _RPMFI_INTERNAL
44 #include "rpmfi.h"
45 #include "fsm.h" /* XXX CPIO_FOO/IOSM_FOO constants */
46 #define _RPMSQ_INTERNAL
47 #define _RPMPSM_INTERNAL
48 #include "psm.h"
49 #define F_ISSET(_psm, _FLAG) ((_psm)->flags & (RPMPSM_FLAGS_##_FLAG))
50 #define F_SET(_psm, _FLAG) \
51  (*((unsigned *)&(_psm)->flags) |= (RPMPSM_FLAGS_##_FLAG))
52 #define F_CLR(_psm, _FLAG) \
53  (*((unsigned *)&(_psm)->flags) &= ~(RPMPSM_FLAGS_##_FLAG))
54 
55 #define _RPMEVR_INTERNAL
56 #include "rpmds.h"
57 
58 #define _RPMTE_INTERNAL
59 #include "rpmte.h"
60 
61 #define _RPMTS_INTERNAL /* XXX ts->notify */
62 #include "rpmts.h"
63 
64 #include "misc.h" /* XXX rpmMkdirPath, makeTempFile, doputenv */
65 
66 #include <rpmcli.h>
67 
68 #include "debug.h"
69 
70 #define PATT_ISDIR(patt, len) ((patt[0] == '/' && patt[len-1] == '/') || \
71  (patt[0] == '^' && patt[len-1] == '$' && patt[len-2] == '/'))
72 
73 #define _PSM_DEBUG 0
74 /*@unchecked@*/
76 /*@unchecked@*/
77 int _psm_threads = 0;
78 
79 /*@access FD_t @*/ /* XXX void * arg */
80 /*@access Header @*/ /* XXX void * arg */
81 /*@access miRE @*/
82 
83 /*@access rpmpsm @*/
84 
85 /*@access rpmfi @*/
86 /*@access rpmte @*/ /* XXX rpmInstallSourcePackage */
87 /*@access rpmts @*/ /* XXX ts->notify */
88 
89 /*@access rpmluav @*/
90 
91 #ifdef __cplusplus
92 GENfree(HE_t)
93 GENfree(int *)
94 GENfree(const struct stat *)
95 #endif /* __cplusplus */
96 
97 #ifdef DYING
98 
103 static rpmRC markReplacedFiles(const rpmpsm psm)
104  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
105  /*@modifies psm, rpmGlobalMacroContext, fileSystem, internalState @*/
106 {
107  HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he));
108  const rpmts ts = psm->ts;
109  rpmte te = psm->te;
110  rpmfi fi = psm->fi;
111  sharedFileInfo replaced = (te ? te->replaced : NULL);
112  sharedFileInfo sfi;
113  rpmmi mi;
114  Header h;
115  uint32_t * offsets;
116  rpmuint32_t prev;
117  int num;
118  int xx;
119 
120  if (!(rpmfiFC(fi) > 0 && replaced != NULL))
121  return RPMRC_OK;
122 
123  num = prev = 0;
124  for (sfi = replaced; sfi->otherPkg; sfi++) {
125  if (prev && prev == sfi->otherPkg)
126  continue;
127  prev = sfi->otherPkg;
128  num++;
129  }
130  if (num == 0)
131  return RPMRC_OK;
132 
133  offsets = (uint32_t *) alloca(num * sizeof(*offsets));
134  offsets[0] = 0;
135  num = prev = 0;
136  for (sfi = replaced; sfi->otherPkg; sfi++) {
137  if (prev && prev == sfi->otherPkg)
138  continue;
139  prev = sfi->otherPkg;
140  offsets[num++] = sfi->otherPkg;
141  }
142 
143  mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, NULL, 0);
144  xx = rpmmiGrow(mi, offsets, num);
145  xx = rpmmiSetRewrite(mi, 1);
146 
147  sfi = replaced;
148  while ((h = rpmmiNext(mi)) != NULL) {
149  int modified;
150 
151  modified = 0;
152 
153  /* XXX FIXME: not correct yet, but headerGetEntry needs to die now! */
154  he->tag = RPMTAG_FILESTATES;
155  xx = headerGet(h, he, 0);
156  if (!xx)
157  continue;
158 
159  prev = rpmmiInstance(mi);
160  num = 0;
161  while (sfi->otherPkg && sfi->otherPkg == prev) {
162 assert(sfi->otherFileNum < he->c);
163  if (he->p.ui8p[sfi->otherFileNum] != RPMFILE_STATE_REPLACED) {
164  he->p.ui8p[sfi->otherFileNum] = RPMFILE_STATE_REPLACED;
165  if (modified == 0) {
166  /* Modified header will be rewritten. */
167  modified = 1;
168  xx = rpmmiSetModified(mi, modified);
169  }
170  num++;
171  }
172  sfi++;
173  }
174  he->p.ptr = _free(he->p.ptr);
175  }
176  mi = rpmmiFree(mi);
177 
178  return RPMRC_OK;
179 }
180 #endif
181 
182 static rpmRC createDir(rpmts ts, rpmfi fi, const char ** fn, const char * name)
183  /*@globals rpmGlobalMacroContext @*/
184  /*@modifies *fn, rpmGlobalMacroContext @*/
185 {
186  const char * N = rpmGenPath(rpmtsRootDir(ts), name, "");
187  char * t = xstrdup(name+2);
188  rpmRC rc;
189 
190  t[strlen(t)-1] = '\0';
191 
192  rc = rpmMkdirPath(N, t+1);
193  if (rc != RPMRC_OK) {
194  if (Access(N, W_OK))
195  rpmlog(RPMLOG_ERR, _("cannot write to %%%s %s\n"), t, N);
196  else if (fi)
197  Chown(N, fi->uid, fi->gid);
198  }
199 
200  if (fn)
201  *fn = N;
202  else
203  N = _free(N);
204  t = _free(t);
205 
206  return rc;
207 }
208 
210  const char ** specFilePtr, const char ** cookie)
211 {
212  HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he));
213  FD_t fd = (FD_t) _fd;
214  rpmfi fi = NULL;
215  rpmte p = NULL;
216  rpmpsm psm = NULL;
217  Header h = NULL;
218  int isSource;
219  rpmRC rc;
220  int i;
221 
222 /*@-mods@*/ /* Avoid void * _fd annotations for now. */
223  rc = rpmReadPackageFile(ts, fd, __FUNCTION__, &h);
224 /*@=mods@*/
225  switch (rc) {
226  case RPMRC_NOTTRUSTED:
227  case RPMRC_NOKEY:
228  case RPMRC_OK:
229  break;
230  default:
231  goto exit;
232  /*@notreached@*/ break;
233  }
234  if (h == NULL)
235  goto exit;
236 
237  rc = RPMRC_FAIL; /* assume failure */
238 
239  isSource =
240  (headerIsEntry(h, RPMTAG_SOURCERPM) == 0 &&
241  headerIsEntry(h, RPMTAG_ARCH) != 0);
242 
243  if (!isSource) {
244  rpmlog(RPMLOG_ERR, _("source package expected, binary found\n"));
245  goto exit;
246  }
247 
248  (void) rpmtsAddInstallElement(ts, h, NULL, 0, NULL);
249 
250  p = rpmtsElement(ts, 0);
251 assert(p->h == NULL);
252  (void) rpmteSetHeader(p, h);
253 /*@-mods@*/ /* LCL: avoid void * _fd annotation for now. */
254 /*@-assignexpose -castexpose -temptrans @*/
255  p->fd = fdLink(fd, __FUNCTION__);
256 /*@=assignexpose =castexpose =temptrans @*/
257 /*@=mods@*/
258 
259  fi = rpmteFI(p, RPMTAG_BASENAMES);
260  fi->h = headerLink(h);
261 /*@-onlytrans@*/ /* FIX: te reference */
262  fi->te = p;
263 /*@=onlytrans@*/
264 
265  /* XXX FIXME: don't do per-file mapping, force global flags. */
266  fi->fmapflags = _free(fi->fmapflags);
268 
269  fi->uid = getuid();
270  fi->gid = getgid();
271 #if defined(RPM_VENDOR_OPENPKG) /* switch-from-susr-to-musr-on-srpm-install */
272  /* If running as the OpenPKG "susr", do not unpack source RPM
273  packages with "susr" file ownerships as the OpenPKG Set-UID
274  wrapper switches from "musr" to "susr" on "openpkg rpm -Uvh
275  *.src.rpm". As a result the installed files could be never
276  removed again by "musr". It is more consistent to always unpack
277  as "musr" if possible. */
278  if (fi->uid == 0) {
279  char *muid_str;
280  char *mgid_str;
281  uid_t muid;
282  gid_t mgid;
283  if ((muid_str = rpmExpand("%{l_muid}", NULL)) != NULL)
284  if ((muid = (uid_t)strtol(muid_str, (char **)NULL, 10)) > 0)
285  fi->uid = muid;
286  if ((mgid_str = rpmExpand("%{l_mgid}", NULL)) != NULL)
287  if ((mgid = (gid_t)strtol(mgid_str, (char **)NULL, 10)) > 0)
288  fi->gid = mgid;
289  }
290 #endif
291  for (i = 0; i < (int)fi->fc; i++)
292  fi->actions[i] = FA_CREATE;
293 
294  /* Load relative (in a *.src.rpm) file paths as an argv array. */
295  fi->astriplen = 0;
296  fi->striplen = 0;
297  he->tag = RPMTAG_FILEPATHS;
298  if (!headerGet(h, he, 0) || he->p.argv == NULL || he->p.argv[0] == NULL)
299  goto exit;
300  fi->apath = he->p.argv;
301 
302  (void) headerMacrosLoad(h);
303 
304 #if defined(RPM_VENDOR_OPENPKG) /* switch-from-susr-to-musr-on-srpm-install */
305  if (createDir(ts, fi, NULL, "%{_topdir}")
306  || createDir(ts, fi, NULL, "%{_builddir}")
307  || createDir(ts, fi, NULL, "%{_rpmdir}")
308  || createDir(ts, fi, NULL, "%{_srcrpmdir}")
309  || createDir(ts, fi, NULL, "%{_sourcedir}")
310  || createDir(ts, fi, NULL, "%{_specdir}"))
311 #else
312  if (createDir(ts, NULL, NULL, "%{_topdir}")
313  || createDir(ts, NULL, NULL, "%{_builddir}")
314  || createDir(ts, NULL, NULL, "%{_rpmdir}")
315  || createDir(ts, NULL, NULL, "%{_srcrpmdir}")
316  || createDir(ts, NULL, NULL, "%{_sourcedir}")
317  || createDir(ts, NULL, NULL, "%{_specdir}"))
318 #endif
319  goto exit;
320 
321  /* Retrieve build cookie. */
322  if (cookie) {
323  *cookie = NULL;
324  he->tag = RPMTAG_COOKIE;
325  if (headerGet(h, he, 0)) *cookie = he->p.str;
326  }
327 
328  /* Find spec file path. */
329  if (specFilePtr) {
330  *specFilePtr = NULL;
331  fi = rpmfiInit(fi, 0);
332  while ((i = rpmfiNext(fi)) >= 0) {
333  if (!(rpmfiFFlags(fi) & RPMFILE_SPECFILE))
334  continue;
335  *specFilePtr = xstrdup(rpmfiFN(fi));
336  break;
337  }
338  if (*specFilePtr == NULL) {
339  rpmlog(RPMLOG_ERR, _("source package contains no .spec file\n"));
340  goto exit;
341  }
342  }
343 
344  /* Unpack the SRPM contents. */
345  psm = rpmpsmNew(ts, p, fi);
346  psm->goal = PSM_PKGINSTALL;
347  rc = rpmpsmStage(psm, PSM_PROCESS);
348  (void) rpmpsmStage(psm, PSM_FINI);
349  psm = rpmpsmFree(psm, __FUNCTION__);
350 
351 exit:
352  if (rc != RPMRC_OK) {
353  if (specFilePtr) *specFilePtr = _free(*specFilePtr);
354  if (cookie) *cookie = _free(*cookie);
355  }
356 
357  if (fi)
358  fi->te = NULL;
359 
360  if (p) {
361  (void) rpmteSetHeader(p, NULL);
362 /*@-mods@*/ /* Avoid void * _fd annotations for now. */
363  if (p->fd != NULL)
364  (void) Fclose(p->fd);
365 /*@=mods@*/
366  p->fd = NULL;
367  }
368 
369  /* XXX nuke the added package(s). */
370  rpmtsClean(ts);
371 
372  (void) headerFree(h);
373  h = NULL;
374 
375  return rc;
376 }
377 
378 /*@observer@*/ /*@unchecked@*/
379 static const char * SCRIPT_PATH =
380  "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin";
381 
387 static /*@observer@*/ const char * tag2sln(rpmTag tag)
388  /*@*/
389 {
390  switch (tag) {
391  case RPMTAG_PRETRANS: return "%pretrans";
392  case RPMTAG_TRIGGERPREIN: return "%triggerprein";
393  case RPMTAG_PREIN: return "%pre";
394  case RPMTAG_POSTIN: return "%post";
395  case RPMTAG_TRIGGERIN: return "%triggerin";
396  case RPMTAG_TRIGGERUN: return "%triggerun";
397  case RPMTAG_PREUN: return "%preun";
398  case RPMTAG_POSTUN: return "%postun";
399  case RPMTAG_POSTTRANS: return "%posttrans";
400  case RPMTAG_TRIGGERPOSTUN: return "%triggerpostun";
401  case RPMTAG_VERIFYSCRIPT: return "%verify";
402  case RPMTAG_SANITYCHECK: return "%sanitycheck";
403  case RPMTAG_BUILDPREP: return "%prep";
404  case RPMTAG_BUILDBUILD: return "%build";
405  case RPMTAG_BUILDINSTALL: return "%install";
406  case RPMTAG_BUILDCHECK: return "%check";
407  default: break;
408  }
409  return "%unknownscript";
410 }
411 
418  /*@*/
419 {
420  switch (tag) {
421  case RPMTAG_PRETRANS: return RPMSCRIPT_PRETRANS;
423  case RPMTAG_PREIN: return RPMSCRIPT_PREIN;
424  case RPMTAG_POSTIN: return RPMSCRIPT_POSTIN;
427  case RPMTAG_PREUN: return RPMSCRIPT_PREUN;
428  case RPMTAG_POSTUN: return RPMSCRIPT_POSTUN;
433  case RPMTAG_BUILDPREP: return RPMSCRIPT_PREP;
434  case RPMTAG_BUILDBUILD: return RPMSCRIPT_BUILD;
436  case RPMTAG_BUILDCHECK: return RPMSCRIPT_CHECK;
437  default: break;
438  }
439  return RPMSCRIPT_MAX;
440 }
441 
447 static pid_t psmWait(rpmpsm psm)
448  /*@globals fileSystem, internalState @*/
449  /*@modifies psm, fileSystem, internalState @*/
450 {
451  const rpmts ts = psm->ts;
452  rpmtime_t msecs;
453 
454  (void) rpmsqWait(&psm->sq);
455  msecs = psm->sq.op.usecs/1000;
456  (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_SCRIPTLETS), &psm->sq.op);
457 
459  D_("%s: waitpid(%d) rc %d status %x secs %u.%03u\n"),
460  psm->stepName, (unsigned)psm->sq.child,
461  (unsigned)psm->sq.reaped, psm->sq.status,
462  (unsigned)msecs/1000, (unsigned)msecs%1000);
463 
464  if (psm->sstates != NULL)
465  { rpmuint32_t * ssp = psm->sstates + tag2slx(psm->scriptTag);
466  *ssp &= ~0xffff;
467  *ssp |= (psm->sq.status & 0xffff);
468  *ssp |= RPMSCRIPT_STATE_REAPED;
469  }
470 
471  return psm->sq.reaped;
472 }
473 
474 #ifdef WITH_LUA
475 
486 static rpmRC runLuaScript(rpmpsm psm, const char * sln, HE_t Phe,
487  const char *script, int arg1, int arg2)
488  /*@globals fileSystem, internalState @*/
489  /*@modifies psm, fileSystem, internalState @*/
490 {
491  rpmRC rc = RPMRC_OK;
492  int xx;
493  rpmlua lua = NULL; /* Global state. */
494  rpmluav var;
495 
496  /* Create arg variable */
497  rpmluaPushTable(lua, "arg");
498  var = rpmluavNew();
499  rpmluavSetListMode(var, 1);
500 /*@+relaxtypes@*/
501  if (Phe->p.argv) {
502  int i;
503  for (i = 0; i < (int)Phe->c && Phe->p.argv[i]; i++) {
504  rpmluavSetValue(var, RPMLUAV_STRING, Phe->p.argv[i]);
505  rpmluaSetVar(lua, var);
506  }
507  }
508  if (arg1 >= 0) {
509  rpmluavSetValueNum(var, arg1);
510  rpmluaSetVar(lua, var);
511  }
512  if (arg2 >= 0) {
513  rpmluavSetValueNum(var, arg2);
514  rpmluaSetVar(lua, var);
515  }
516 /*@=relaxtypes@*/
517 /*@-moduncon@*/
518  var = (rpmluav) rpmluavFree(var);
519 /*@=moduncon@*/
520  rpmluaPop(lua);
521 
522  { char buf[BUFSIZ];
523  xx = snprintf(buf, BUFSIZ, "%s(%s)", sln, psm->NVRA);
524  xx = rpmluaRunScript(lua, script, buf);
525  if (xx == -1) {
526  void * ptr = rpmtsNotify(psm->ts, psm->te, RPMCALLBACK_SCRIPT_ERROR,
527  psm->scriptTag, 1);
528  ptr = ptr; /* XXX keep gcc happy. */
529  rc = RPMRC_FAIL;
530  } else
531  rc = RPMRC_OK;
532  }
533  rpmluaDelVar(lua, "arg");
534 
535  return rc;
536 }
537 #endif /* WITH_LUA */
538 
539 #if defined(_WITH_EMBEDDED)
540 static int enterChroot(rpmpsm psm, int * pwdFdnop, int * rootFdnop)
541  /*@globals fileSystem, internalState @*/
542  /*@modifies *pwdFdnop, *rootFdnop, fileSystem, internalState @*/
543 {
544  const rpmts ts = psm->ts;
545  int inChroot;
546  int xx;
547 
548  /* Save the current working directory. */
549  if (pwdFdnop)
550  (*pwdFdnop) = open(".", O_RDONLY, 0);
551 
552  /* Save the current root directory. */
553  if (rootFdnop)
554  (*rootFdnop) = open("/", O_RDONLY, 0);
555 
556  /* Get into the chroot. */
557  if (!rpmtsChrootDone(ts)) {
558  const char *rootDir = rpmtsRootDir(ts);
559  inChroot = 0;
560  /*@-modobserver @*/
561  if (rootDir != NULL && strcmp(rootDir, "/") && *rootDir == '/') {
562  xx = Chroot(rootDir);
563  /*@=modobserver @*/
564  xx = rpmtsSetChrootDone(ts, 1);
565  }
566  } else
567  inChroot = 1;
568 
569  /* All embedded scriptlets run with CWD == "/". */
570  xx = Chdir("/");
571 
572  return inChroot;
573 }
574 
575 static int exitChroot(rpmpsm psm, int inChroot, int pwdFdno, int rootFdno)
576  /*@globals fileSystem, internalState @*/
577  /*@modifies psm, fileSystem, internalState @*/
578 {
579  const rpmts ts = psm->ts;
580  const char *rootDir = rpmtsRootDir(ts);
581  int xx;
582 
583  if (rpmtsChrootDone(ts) && !inChroot) {
584  xx = fchdir(rootFdno);
585 /*@-modobserver@*/
586  if (rootDir != NULL && strcmp(rootDir, "/") && *rootDir == '/') {
587  xx = Chroot(".");
588 /*@=modobserver@*/
589  xx = rpmtsSetChrootDone(ts, 0);
590  }
591  xx = fchdir(pwdFdno);
592  } else
593  xx = fchdir(pwdFdno);
594 
595  xx = close(rootFdno);
596  xx = close(pwdFdno);
597 
598  return 0;
599 }
600 
612 static rpmRC runEmbeddedScript(rpmpsm psm, const char * sln, HE_t Phe,
613  const char *script, int arg1, int arg2, ARGV_t matches)
614  /*@globals fileSystem, internalState @*/
615  /*@modifies psm, fileSystem, internalState @*/
616 {
617  char ** av = NULL;
618  int pwdFdno = -1;
619  int rootFdno = -1;
620  rpmRC rc = RPMRC_OK;
621  int xx = 0;
622  rpmuint32_t * ssp = NULL;
623  int inChroot = enterChroot(psm, &pwdFdno, &rootFdno);
624  size_t len = 4 + (matches ? argvCount(matches) : 0);
625 
626  if (psm->sstates != NULL)
627  ssp = psm->sstates + tag2slx(psm->scriptTag);
628  if (ssp != NULL)
630 
631  av = alloca(len * sizeof(*av));
632  if (arg1 >= 0)
633  (void) sprintf((av[1] = (char *) alloca(32)), "%d", arg1);
634  else
635  av[1] = NULL;
636  if (arg2 >= 0)
637  (void) sprintf((av[2] = (char *) alloca(32)), "%d", arg2);
638  else
639  av[2] = NULL;
640  if (matches)
641  memcpy(&av[3], argvData(matches), argvCount(matches) * sizeof(*argvData(matches)));
642  av[len-1] = NULL;
643 
644 
645 #if defined(WITH_LUA)
646  if (!strcmp(Phe->p.argv[0], "<lua>")) {
647  rc = runLuaScript(psm, sln, Phe, script, arg1, arg2);
648  } else
649 #endif
650 #if defined(WITH_AUGEAS)
651  if (!strcmp(Phe->p.argv[0], "<augeas>")) {
652  /* XXX change rpmaugNew() to common embedded interpreter API */
653  rpmaug aug = NULL;
654  rc = rpmaugRun(aug, script, NULL) == RPMRC_OK
655  ? RPMRC_OK : RPMRC_FAIL;
656  aug = rpmaugFree(aug);
657  } else
658 #endif
659 #if defined(WITH_FICL)
660  if (!strcmp(Phe->p.argv[0], "<ficl>")) {
661  rpmficl ficl = rpmficlNew((char **)av, 0);
662  rc = rpmficlRun(ficl, script, NULL) == RPMRC_OK
663  ? RPMRC_OK : RPMRC_FAIL;
664  ficl = rpmficlFree(ficl);
665  } else
666 #endif
667 #if defined(WITH_GPSEE)
668  if (!strcmp(Phe->p.argv[0], "<js>")) {
669  rpmjs js = rpmjsNew((char **)av, 0);
670  rc = rpmjsRun(js, script, NULL) == RPMRC_OK
671  ? RPMRC_OK : RPMRC_FAIL;
672  js = rpmjsFree(js);
673  } else
674 #endif
675 #if defined(WITH_PERLEMBED)
676  if (!strcmp(Phe->p.argv[0], "<perl>")) {
677  rpmperl perl = rpmperlNew((char **)av, 0);
678  rc = rpmperlRun(perl, script, NULL) == RPMRC_OK
679  ? RPMRC_OK : RPMRC_FAIL;
680  perl = rpmperlFree(perl);
681  } else
682 #endif
683 #if defined(WITH_PYTHONEMBED)
684  if (!strcmp(Phe->p.argv[0], "<python>")) {
685  rpmpython python = rpmpythonNew((char **)av, 0);
686  rc = rpmpythonRun(python, script, NULL) == RPMRC_OK
687  ? RPMRC_OK : RPMRC_FAIL;
688  python = rpmpythonFree(python);
689  } else
690 #endif
691 #if defined(WITH_RUBY)
692  if (!strcmp(Phe->p.argv[0], "<ruby>")) {
693  rpmruby ruby = rpmrubyNew((char **)av, 0);
694  rc = rpmrubyRun(ruby, script, NULL) == RPMRC_OK
695  ? RPMRC_OK : RPMRC_FAIL;
696  ruby = rpmrubyFree(ruby);
697  } else
698 #endif
699 #if defined(WITH_SEMANAGE)
700  if (!strcmp(Phe->p.argv[0], "<spook>")) {
701  /* XXX change rpmsmNew() to common embedded interpreter API */
702  rpmsm sm = NULL;
703  /* XXX HACK: use an argv for now. */
704  const char * av[2];
705  av[0] = script;
706  av[1] = NULL;
707  rc = rpmsmRun(sm, (char **)av, NULL) == RPMRC_OK
708  ? RPMRC_OK : RPMRC_FAIL;
709  sm = rpmsmFree(sm);
710  } else
711 #endif
712 #if defined(WITH_SQLITE)
713  if (!strcmp(Phe->p.argv[0], "<sql>")) {
714  int Pac = Phe->c;
715  const char ** Pav = (const char **) xmalloc((Pac + 1) * sizeof(*Pav));
716  const char * result = NULL;
717  rpmsql sql;
718  int i;
719 
720  /* XXX ignore $1/$2, copy the tag array instead. */
721  /* XXX no NULL sentinel in tag arrays. */
722  for (i = 0; i < Pac; i++)
723  Pav[i] = rpmExpand(Phe->p.argv[i], NULL);
724  Pav[Pac] = NULL;
725 
726  sql = rpmsqlNew((char **)Pav, 0);
727  rc = rpmsqlRun(sql, script, &result) == RPMRC_OK
728  ? RPMRC_OK : RPMRC_FAIL;
729  sql = rpmsqlFree(sql);
730  Pav = argvFree(Pav);
731  } else
732 #endif
733 #if defined(WITH_SQUIRREL)
734  if (!strcmp(Phe->p.argv[0], "<squirrel>")) {
735  rpmsquirrel squirrel = rpmsquirrelNew((char **)av, 0);
736  rc = rpmsquirrelRun(squirrel, script, NULL) == RPMRC_OK
737  ? RPMRC_OK : RPMRC_FAIL;
738  squirrel = rpmsquirrelFree(squirrel);
739  } else
740 #endif
741 #if defined(WITH_TCL)
742  if (!strcmp(Phe->p.argv[0], "<tcl>")) {
743  rpmtcl tcl = rpmtclNew((char **)av, 0);
744  rc = rpmtclRun(tcl, script, NULL) == RPMRC_OK
745  ? RPMRC_OK : RPMRC_FAIL;
746  tcl = rpmtclFree(tcl);
747  } else
748 #endif
749  rc = RPMRC_NOTFOUND;
750 
751  if (ssp != NULL) {
752  *ssp &= ~0xffff;
753  *ssp |= (xx & 0xffff);
754  *ssp |= RPMSCRIPT_STATE_REAPED;
755  }
756 
757  xx = exitChroot(psm, inChroot, pwdFdno, rootFdno);
758 
759  return rc;
760 }
761 #endif
762 
765 /*@unchecked@*/
766 static int ldconfig_done = 0;
767 
768 /*@unchecked@*/ /*@observer@*/ /*@null@*/
769 static const char * ldconfig_path = "/sbin/ldconfig";
770 
787 static rpmRC runScript(rpmpsm psm, Header h, const char * sln, HE_t Phe,
788  const char * script, int arg1, int arg2, ARGV_t matches)
789  /*@globals ldconfig_done, rpmGlobalMacroContext, h_errno,
790  fileSystem, internalState@*/
791  /*@modifies psm, ldconfig_done, rpmGlobalMacroContext,
792  fileSystem, internalState @*/
793 {
794  const rpmts ts = psm->ts;
795  const char * NVRA = psm->NVRA;
796  HE_t IPhe = psm->IPhe;
797  const char ** argv = NULL;
798  int argc = 0;
799  const char ** IP = NULL;
800  int nIP;
801  size_t maxPrefixLength;
802  size_t len;
803  char * prefixBuf = NULL;
804  const char * fn = NULL;
805  FD_t scriptFd = NULL;
806  FD_t out = NULL; /* exit: expects this to be initialized. */
807  rpmRC rc = RPMRC_FAIL; /* assume failure */
808  const char * body = NULL;
809  rpmop op = (rpmop) memset(alloca(sizeof(*op)), 0, sizeof(*op));
810  int ix = tag2slx(psm->scriptTag);
811  rpmuint32_t * ssp = NULL;
812  pid_t pid;
813  int xx;
814  int i;
815 
816  if (psm->sstates != NULL && ix >= 0 && ix < RPMSCRIPT_MAX)
817  ssp = psm->sstates + ix;
818  if (ssp != NULL)
820 
821  if (Phe->p.argv == NULL && script == NULL)
822  return RPMRC_OK;
823 
824  /* Macro expand all scriptlets. */
825  body = rpmExpand(script, NULL);
826 
827  /* XXX Load NVRA lazily. This should be done elsewhere ... */
828  if (NVRA == NULL) {
829  HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he));
830  he->tag = RPMTAG_NVRA;
831  xx = headerGet(h, he, 0);
832 assert(he->p.str != NULL);
833  psm->NVRA = NVRA = he->p.str;
834  }
835 
836  if (op != NULL)
837  (void) rpmswEnter(op, 0);
838 
839  if (Phe->p.argv && Phe->p.argv[0])
840  if (!strcmp(Phe->p.argv[0], "<lua>")
841  || !strcmp(Phe->p.argv[0], "<augeas>")
842  || !strcmp(Phe->p.argv[0], "<ficl>")
843  || !strcmp(Phe->p.argv[0], "<js>")
844  || !strcmp(Phe->p.argv[0], "<perl>")
845  || !strcmp(Phe->p.argv[0], "<python>")
846  || !strcmp(Phe->p.argv[0], "<ruby>")
847  || !strcmp(Phe->p.argv[0], "<sql>")
848  || !strcmp(Phe->p.argv[0], "<squirrel>")
849  || !strcmp(Phe->p.argv[0], "<tcl>"))
850  {
851 #if defined(_WITH_EMBEDDED)
853  D_("%s: %s(%s) running %s scriptlet.\n"),
854  psm->stepName, tag2sln(psm->scriptTag), NVRA, Phe->p.argv[0]);
855  rc = runEmbeddedScript(psm, sln, Phe, body, arg1, arg2, matches);
856 #endif
857  goto exit;
858  }
859 
860  psm->sq.reaper = 1;
861 
862  /*
863  * If a successor node, and ldconfig was just run, don't bother.
864  */
865  if (ldconfig_path && Phe->p.argv != NULL && F_ISSET(psm, UNORDERED)) {
866  if (ldconfig_done && !strcmp(Phe->p.argv[0], ldconfig_path)) {
868  D_("%s: %s(%s) skipping redundant \"%s\".\n"),
869  psm->stepName, tag2sln(psm->scriptTag), NVRA,
870  Phe->p.argv[0]);
871  rc = RPMRC_OK;
872  goto exit;
873  }
874  }
875 
877  D_("%s: %s(%s) %ssynchronous scriptlet start\n"),
878  psm->stepName, tag2sln(psm->scriptTag), NVRA,
879  (F_ISSET(psm, UNORDERED) ? "a" : ""));
880 
881  if (Phe->p.argv == NULL) {
882  argv = alloca(5 + (matches ? argvCount(matches) : 0 ) * sizeof(*argv));
883  argv[0] = "/bin/sh";
884  argc = 1;
885  ldconfig_done = 0;
886  } else {
887  argv = alloca((Phe->c + 4) + (matches ? argvCount(matches) : 0 ) * sizeof(*argv));
888  memcpy(argv, Phe->p.argv, Phe->c * sizeof(*argv));
889  argc = Phe->c;
890  ldconfig_done = (ldconfig_path && !strcmp(argv[0], ldconfig_path)
891  ? 1 : 0);
892  }
893 
894  /* XXX Load INSTPREFIXES lazily. This should be done elsewhere ... */
895  if (IPhe->tag == 0) {
896  IPhe->tag = RPMTAG_INSTPREFIXES;
897  xx = headerGet(h, IPhe, 0);
898  if (!xx) {
899  IPhe->p.ptr = _free(IPhe->p.ptr);
900  IPhe->tag = RPMTAG_INSTALLPREFIX;
901  xx = headerGet(h, IPhe, 0);
902  if (xx) {
903  const char ** av = (const char **)
904  xmalloc(sizeof(*av) + strlen(IPhe->p.argv[0]) + 1);
905  char * t = (char *) &av[1];
906 
907  av[0] = t;
908  t = stpcpy(t, IPhe->p.argv[0]);
909  *t = '\0';
910  IPhe->p.ptr = _free(IPhe->p.ptr);
911  IPhe->t = RPM_STRING_ARRAY_TYPE;
912  IPhe->p.argv = av;
913  IPhe->c = 1;
914  } else {
915  IPhe->p.argv = NULL;
916  IPhe->c = 0;
917  }
918  }
919  }
920  IP = IPhe->p.argv;
921  nIP = IPhe->c;
922 
923  maxPrefixLength = 0;
924  if (IP != NULL)
925  for (i = 0; i < nIP; i++) {
926  len = strlen(IP[i]);
927  if (len > maxPrefixLength) maxPrefixLength = len;
928  }
929  prefixBuf = (char *) alloca(maxPrefixLength + 50);
930 
931  if (script) {
932  const char * rootDir = rpmtsRootDir(ts);
933  FD_t fd;
934  size_t nw;
935 
936  if (rpmTempFile((!rpmtsChrootDone(ts) ? rootDir : "/"), &fn, &fd))
937  goto exit;
938 
939  if (rpmIsDebug() &&
940  (!strcmp(argv[0], "/bin/sh") || !strcmp(argv[0], "/bin/bash")))
941  {
942  static const char set_x[] = "set -x\n";
943  nw = Fwrite(set_x, sizeof(set_x[0]), sizeof(set_x)-1, fd);
944  }
945 
946  if (ldconfig_path && strstr(body, ldconfig_path) != NULL)
947  ldconfig_done = 1;
948 
949  nw = Fwrite(body, sizeof(body[0]), strlen(body), fd);
950  xx = Fclose(fd);
951 
952  { const char * sn = fn;
953  if (!rpmtsChrootDone(ts) && rootDir != NULL &&
954  !(rootDir[0] == '/' && rootDir[1] == '\0'))
955  {
956  sn += strlen(rootDir)-1;
957  }
958  argv[argc++] = sn;
959  }
960 
961  if (arg1 >= 0) {
962  char *av = (char *) alloca(20);
963  sprintf(av, "%d", arg1);
964  argv[argc++] = av;
965  }
966  if (arg2 >= 0) {
967  char *av = (char *) alloca(20);
968  sprintf(av, "%d", arg2);
969  argv[argc++] = av;
970  }
971  if (matches) {
972  memcpy(&argv[argc], argvData(matches), argvCount(matches) * sizeof(*argvData(matches)));
973  argc += argvCount(matches);
974  }
975  }
976 
977  argv[argc] = NULL;
978 
979  /* Log the scriptlet to be exec'd. */
980  switch (psm->scriptTag) {
981  default:
982  break;
983  case RPMTAG_PREIN:
984  (void) rpmlioPrein(rpmtsGetRdb(ts), argv, body);
985  break;
986  case RPMTAG_POSTIN:
987  (void) rpmlioPostin(rpmtsGetRdb(ts), argv, body);
988  break;
989  case RPMTAG_PREUN:
990  (void) rpmlioPreun(rpmtsGetRdb(ts), argv, body);
991  break;
992  case RPMTAG_POSTUN:
993  (void) rpmlioPostun(rpmtsGetRdb(ts), argv, body);
994  break;
995  }
996 
997  scriptFd = rpmtsScriptFd(ts);
998  if (scriptFd != NULL) {
999  if (rpmIsVerbose()) {
1000  out = fdDup(Fileno(scriptFd));
1001  } else {
1002  out = Fopen("/dev/null", "w.fdio");
1003  if (Ferror(out)) {
1004  out = fdDup(Fileno(scriptFd));
1005  }
1006  }
1007  } else {
1008  out = fdDup(STDOUT_FILENO);
1009  }
1010  if (out == NULL) /* XXX can't happen */
1011  goto exit;
1012 
1013  pid = rpmsqFork(&psm->sq);
1014  if (psm->sq.child == 0) {
1015  int pipes[2];
1016  int flag;
1017  int fdno;
1018 
1019  pipes[0] = pipes[1] = 0;
1020  /* Make stdin inaccessible */
1021  xx = pipe(pipes);
1022  xx = close(pipes[1]);
1023  xx = dup2(pipes[0], STDIN_FILENO);
1024  xx = close(pipes[0]);
1025 
1026  /* XXX Force FD_CLOEXEC on 1st 100 inherited fdno's. */
1027  for (fdno = 3; fdno < 100; fdno++) {
1028  flag = fcntl(fdno, F_GETFD);
1029  if (flag == -1 || (flag & FD_CLOEXEC))
1030  continue;
1032  D_("%s: %s(%s)\tfdno(%d) missing FD_CLOEXEC\n"),
1033  psm->stepName, sln, NVRA,
1034  fdno);
1035  xx = fcntl(fdno, F_SETFD, FD_CLOEXEC);
1036  /* XXX W2DO? debug msg for inheirited fdno w/o FD_CLOEXEC */
1037  }
1038 
1039  if (scriptFd != NULL) {
1040  int sfdno = Fileno(scriptFd);
1041  int ofdno = Fileno(out);
1042  if (sfdno != STDERR_FILENO)
1043  xx = dup2(sfdno, STDERR_FILENO);
1044  if (ofdno != STDOUT_FILENO)
1045  xx = dup2(ofdno, STDOUT_FILENO);
1046  /* make sure we don't close stdin/stderr/stdout by mistake! */
1047  if (ofdno > STDERR_FILENO && ofdno != sfdno)
1048  xx = Fclose (out);
1049  if (sfdno > STDERR_FILENO && ofdno != sfdno)
1050  xx = Fclose (scriptFd);
1051  }
1052 
1053  { const char *ipath = rpmExpand("PATH=%{_install_script_path}", NULL);
1054  const char *path = SCRIPT_PATH;
1055 
1056  if (ipath && ipath[5] != '%')
1057  path = ipath;
1058 
1059  xx = doputenv(path);
1060  /*@-modobserver@*/
1061  ipath = _free(ipath);
1062  /*@=modobserver@*/
1063  }
1064 
1065  if (IP != NULL)
1066  for (i = 0; i < nIP; i++) {
1067  sprintf(prefixBuf, "RPM_INSTALL_PREFIX%d=%s", i, IP[i]);
1068  xx = doputenv(prefixBuf);
1069 
1070  /* backwards compatibility */
1071  if (i == 0) {
1072  sprintf(prefixBuf, "RPM_INSTALL_PREFIX=%s", IP[i]);
1073  xx = doputenv(prefixBuf);
1074  }
1075  }
1076 
1077  { const char * rootDir = rpmtsRootDir(ts);
1078  if (!rpmtsChrootDone(ts) && rootDir != NULL &&
1079  !(rootDir[0] == '/' && rootDir[1] == '\0'))
1080  {
1081  /*@-modobserver@*/
1082  xx = Chroot(rootDir);
1083  /*@=modobserver@*/
1084  }
1085  xx = Chdir("/");
1086  rpmlog(RPMLOG_DEBUG, D_("%s: %s(%s)\texecv(%s) pid %d\n"),
1087  psm->stepName, sln, NVRA,
1088  argv[0], (unsigned)getpid());
1089 
1090  /* XXX Don't mtrace into children. */
1091  unsetenv("MALLOC_CHECK_");
1092 
1093  if (ssp != NULL)
1094  *ssp |= RPMSCRIPT_STATE_EXEC;
1095 
1096  /* Permit libselinux to do the scriptlet exec. */
1097  if (rpmtsSELinuxEnabled(ts) == 1) {
1098  if (ssp != NULL)
1099  *ssp |= RPMSCRIPT_STATE_SELINUX;
1100  xx = rpmsxExec(NULL, 0, argv);
1101  } else {
1102 /*@-nullstate@*/
1103  xx = execv(argv[0], (char *const *)argv);
1104 /*@=nullstate@*/
1105  }
1106  }
1107 
1108  if (ssp != NULL)
1109  *ssp &= ~RPMSCRIPT_STATE_EXEC;
1110 
1111  _exit(-1);
1112  /*@notreached@*/
1113  }
1114 
1115  if (psm->sq.child == (pid_t)-1) {
1116  rpmlog(RPMLOG_ERR, _("Couldn't fork %s: %s\n"), sln, strerror(errno));
1117  goto exit;
1118  }
1119 
1120  (void) psmWait(psm);
1121 
1122  /* XXX filter order dependent multilib "other" arch helper error. */
1123  if (!(psm->sq.reaped >= 0 && !strcmp(argv[0], "/usr/sbin/glibc_post_upgrade") && WEXITSTATUS(psm->sq.status) == 110)) {
1124  void *ptr = NULL;
1125  if (psm->sq.reaped < 0) {
1127  _("%s(%s) scriptlet failed, waitpid(%d) rc %d: %s\n"),
1128  sln, NVRA, (int)psm->sq.child, (int)psm->sq.reaped,
1129  strerror(errno));
1130  goto exit;
1131  } else
1132  if (!WIFEXITED(psm->sq.status) || WEXITSTATUS(psm->sq.status)) {
1133  if (WIFSIGNALED(psm->sq.status)) {
1134  ptr = rpmtsNotify(ts, psm->te, RPMCALLBACK_SCRIPT_ERROR,
1135  psm->scriptTag, WTERMSIG(psm->sq.status));
1137  _("%s(%s) scriptlet failed, signal %d\n"),
1138  sln, NVRA, WTERMSIG(psm->sq.status));
1139  } else {
1140  ptr = rpmtsNotify(ts, psm->te, RPMCALLBACK_SCRIPT_ERROR,
1141  psm->scriptTag, WEXITSTATUS(psm->sq.status));
1143  _("%s(%s) scriptlet failed, exit status %d\n"),
1144  sln, NVRA, WEXITSTATUS(psm->sq.status));
1145  }
1146  goto exit;
1147  }
1148  }
1149 
1150  rc = RPMRC_OK;
1151 
1152 exit:
1153  if (op != NULL) {
1154  static unsigned int scale = 1000;
1155  (void) rpmswExit(op, 0);
1156  if (ix >= 0 && ix < RPMSCRIPT_MAX)
1157  psm->smetrics[ix] += op->usecs / scale;
1158  }
1159 
1160  if (out)
1161  xx = Fclose(out); /* XXX dup'd STDOUT_FILENO */
1162 
1163  if (script) {
1164  if (!rpmIsDebug() && fn != NULL)
1165  xx = Unlink(fn);
1166  fn = _free(fn);
1167  }
1168 
1169  body = _free(body);
1170 
1171  return rc;
1172 }
1173 
1180  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1181  /*@modifies psm, rpmGlobalMacroContext, fileSystem, internalState @*/
1182 {
1183  HE_t Phe = (HE_t) memset(alloca(sizeof(*Phe)), 0, sizeof(*Phe));
1184  HE_t She = (HE_t) memset(alloca(sizeof(*She)), 0, sizeof(*She));
1185  rpmfi fi = psm->fi;
1186  const char * argv0 = NULL;
1187  rpmRC rc = RPMRC_OK;
1188 
1189 assert(fi->h != NULL);
1190  She->tag = psm->scriptTag;
1191  if (!headerGet(fi->h, She, 0))
1192  goto exit;
1193 
1194  Phe->tag = psm->progTag;
1195  if (!headerGet(fi->h, Phe, 0))
1196  goto exit;
1197 
1198  /* Coerce strings into header argv return. */
1199  if (Phe->t == RPM_STRING_TYPE) {
1200  const char * s = Phe->p.str;
1201  char * t;
1202  Phe->p.argv = (const char **)
1203  xmalloc(sizeof(Phe->p.argv[0]) + strlen(s) + 1);
1204  Phe->p.argv[0] = t = (char *) &Phe->p.argv[1];
1205  t = stpcpy(t, s);
1206  *t = '\0';
1207  s = _free(s);
1208  }
1209 
1210  /* Expand "%script -p %%{interpreter}" macros. */
1211  if (Phe->p.argv[0][0] == '%')
1212  Phe->p.argv[0] = argv0 = rpmExpand(Phe->p.argv[0], NULL);
1213 
1214  rc = runScript(psm, fi->h, tag2sln(psm->scriptTag), Phe,
1215  She->p.str, psm->scriptArg, -1, NULL);
1216 
1217 exit:
1218  argv0 = _free(argv0);
1219  Phe->p.ptr = _free(Phe->p.ptr);
1220  She->p.ptr = _free(She->p.ptr);
1221  return rc;
1222 }
1223 
1224 /*@unchecked@*/
1226 
1235 static rpmRC handleOneTrigger(const rpmpsm psm,
1236  Header sourceH, Header triggeredH, int arg2)
1237  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState@*/
1238  /*@modifies psm, sourceH, triggeredH,
1239  rpmGlobalMacroContext, fileSystem, internalState @*/
1240 {
1241  static int scareMem = 0;
1242  HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he));
1243  HE_t Ihe = (HE_t) memset(alloca(sizeof(*Ihe)), 0, sizeof(*Ihe));
1244  HE_t She = (HE_t) memset(alloca(sizeof(*She)), 0, sizeof(*She));
1245  HE_t Phe = (HE_t) memset(alloca(sizeof(*Phe)), 0, sizeof(*Phe));
1246  miRE mire = NULL;
1247  const rpmts ts = psm->ts;
1248  rpmds Tds = NULL;
1249  rpmds Fds = NULL;
1250  rpmds Dds = NULL;
1251  rpmds Pds = NULL;
1252  const char * sourceName;
1253  const char * triggerName;
1254  rpmRC rc = RPMRC_OK;
1255  int arg1;
1256  int xx;
1257  int i;
1258 
1259  he->tag = RPMTAG_NAME;
1260  xx = headerGet(sourceH, he, 0);
1261  sourceName = he->p.str;
1262 
1263  he->tag = RPMTAG_NAME;
1264  xx = headerGet(triggeredH, he, 0);
1265  triggerName = he->p.str;
1266 
1267  arg1 = rpmdbCountPackages(rpmtsGetRdb(ts), triggerName);
1268  if (arg1 < 0) {
1269  /* XXX W2DO? fails as "execution of script failed" */
1270  rc = RPMRC_FAIL;
1271  goto exit;
1272  }
1273  arg1 += psm->countCorrection;
1274 
1275  Tds = rpmdsNew(triggeredH, RPMTAG_TRIGGERNAME, scareMem);
1276  if (Tds == NULL)
1277  goto exit;
1278  xx = rpmdsSetNoPromote(Tds, 1);
1279 
1280  Ihe->tag = RPMTAG_TRIGGERINDEX;
1281  if (!headerGet(triggeredH, Ihe, 0))
1282  goto exit;
1283 
1284  She->tag = RPMTAG_TRIGGERSCRIPTS;
1285  if (!headerGet(triggeredH, She, 0))
1286  goto exit;
1287 
1289  if (!headerGet(triggeredH, Phe, 0))
1290  goto exit;
1291 
1292  if ((Tds = rpmdsInit(Tds)) != NULL)
1293  while ((i = rpmdsNext(Tds)) >= 0) {
1294  rpmuint32_t Flags = rpmdsFlags(Tds);
1295  char * depName;
1296  ARGV_t matches = NULL;
1297  int bingo;
1298 
1299  /* Skip triggers that are not in this context. */
1300  if (!(Flags & psm->sense))
1301  continue;
1302 
1303  bingo = 0; /* no trigger to fire. */
1304  depName = (char *) rpmdsN(Tds);
1305  if (depName[0] == '^' || depName[0] == '/') {
1306  size_t nb = strlen(depName);
1307  if (depName[0] == '^' || Glob_pattern_p(depName, 0)) {
1308  rpmds ds = NULL;
1309  if (PATT_ISDIR(depName, nb)) {
1310  /* XXX Dirnames w trailing "/" needed. */
1311  if (Dds == NULL)
1312  Dds = rpmdsNew(sourceH, RPMTAG_DIRNAMES, 0x2);
1313  ds = rpmdsLink(Dds, "Triggers");
1314  } else {
1315  if (Fds == NULL)
1316  Fds = rpmdsNew(sourceH, RPMTAG_BASENAMES, 0);
1317  ds = rpmdsLink(Fds, "Triggers");
1318  }
1319  if (mire == NULL)
1320  mire = mireNew(depName[0] == '^' ? RPMMIRE_PCRE : RPMMIRE_GLOB, 0);
1321 
1322  xx = mireRegcomp(mire, depName);
1323  if ((ds = rpmdsInit(ds)) != NULL)
1324  while (rpmdsNext(ds) >= 0) {
1325  const char * N = rpmdsN(ds);
1326  xx = mireRegexec(mire, N, 0);
1327  if (xx < 0)
1328  /*@innercontinue@*/ continue;
1329  bingo = 1;
1330  argvAdd(&matches, N);
1331  }
1332  (void)rpmdsFree(ds);
1333  ds = NULL;
1334  xx = mireClean(mire);
1335  }
1336 
1337  /* If not matched, and directory trigger, try dir names. */
1338  if (!bingo && PATT_ISDIR(depName, nb)) {
1339  /* XXX Dirnames w trailing "/" needed. */
1340  if (Dds == NULL)
1341  Dds = rpmdsNew(sourceH, RPMTAG_DIRNAMES, 0x2);
1342  bingo = rpmdsMatch(Tds, Dds);
1343  }
1344 
1345  /* If not matched, try file paths. */
1346  if (!bingo) {
1347  if (Fds == NULL)
1348  Fds = rpmdsNew(sourceH, RPMTAG_BASENAMES, 0);
1349  bingo = rpmdsMatch(Tds, Fds);
1350  }
1351  }
1352 
1353  /* If trigger not fired yet, try provided dependency match. */
1354  if (!bingo) {
1355  if (Pds == NULL)
1356  Pds = rpmdsNew(sourceH, RPMTAG_PROVIDENAME, 0);
1357  bingo = rpmdsMatch(Tds, Pds);
1358  bingo = rpmdsNegateRC(Tds, bingo);
1359  }
1360  if (!bingo)
1361  continue;
1362 
1363  /* Coerce strings into header argv return. */
1364  { int index = Ihe->p.ui32p[i];
1365  const char * s = Phe->p.argv[index];
1366  char * t;
1367 
1368  he->tag = Phe->tag;
1369  he->t = RPM_STRING_ARRAY_TYPE;
1370  he->c = 1;
1371  he->p.argv = (const char **)
1372  xmalloc(sizeof(Phe->p.argv[0]) + strlen(s) + 1);
1373  he->p.argv[0] = t = (char *) &he->p.argv[1];
1374  t = stpcpy(t, s);
1375  *t = '\0';
1376 
1377  if (runScript(psm, triggeredH, "%trigger", he,
1378  She->p.argv[index], arg1, arg2, matches))
1379  rc = RPMRC_FAIL;
1380 
1381  he->p.ptr = _free(he->p.ptr);
1382  }
1383  argvFree(matches);
1384  }
1385 
1386  mire = mireFree(mire);
1387  (void)rpmdsFree(Pds);
1388  Pds = NULL;
1389  (void)rpmdsFree(Dds);
1390  Dds = NULL;
1391  (void)rpmdsFree(Fds);
1392  Fds = NULL;
1393  (void)rpmdsFree(Tds);
1394  Tds = NULL;
1395 
1396 exit:
1397  Ihe->p.ptr = _free(Ihe->p.ptr);
1398  She->p.ptr = _free(She->p.ptr);
1399  Phe->p.ptr = _free(Phe->p.ptr);
1400  triggerName = _free(triggerName);
1401  sourceName = _free(sourceName);
1402 
1403  return rc;
1404 }
1405 
1406 /* Retrieve trigger patterns from rpmdb. */
1407 static int rpmdbTriggerGlobs(rpmpsm psm)
1408  /*@globals rpmGlobalMacroContext @*/
1409  /*@modifies psm, rpmGlobalMacroContext @*/
1410 {
1411  const rpmts ts = psm->ts;
1412  ARGV_t keys = NULL;
1414  RPMMIRE_STRCMP, NULL, &keys);
1415  int nkeys = argvCount(keys);
1416  int i;
1417 
1418  if (keys)
1419  for (i = 0; i < nkeys; i++) {
1420  char * t = (char *) keys[i];
1421  if (!(t[0] == '^' || Glob_pattern_p(t, 0)))
1422  continue;
1423  xx = mireAppend(t[0] == '^' ? RPMMIRE_PCRE : RPMMIRE_GLOB, 0, t, NULL,
1424  (miRE *)&psm->Tmires, &psm->nTmires);
1425  xx = argvAdd(&psm->Tpats, t);
1426  }
1427  keys = argvFree(keys);
1428  return 0;
1429 }
1430 
1438 static rpmRC runTriggersLoop(rpmpsm psm, rpmTag tagno, int arg2)
1439  /*@globals rpmGlobalMacroContext, h_errno,
1440  fileSystem, internalState @*/
1441  /*@modifies psm, rpmGlobalMacroContext,
1442  fileSystem, internalState @*/
1443 {
1444  static int scareMem = 0;
1445  const rpmts ts = psm->ts;
1446  rpmfi fi = psm->fi;
1447  rpmds ds = rpmdsNew(fi->h, tagno, scareMem);
1448  char * depName = NULL;
1449  ARGI_t instances = NULL;
1450  rpmmi mi;
1451  Header triggeredH;
1452  rpmRC rc = RPMRC_OK;
1453  int i;
1454  int xx;
1455 
1456  /* Fire elements against rpmdb trigger strings. */
1457  if ((ds = rpmdsInit(ds)) != NULL)
1458  while ((i = rpmdsNext(ds)) >= 0) {
1459  const char * Name = rpmdsN(ds);
1460  size_t nName = strlen(Name);
1461  unsigned prev, instance;
1462  unsigned nvals;
1463  ARGint_t vals;
1464 
1465  depName = _free(depName);
1466  if (!strcmp(Name, "/"))
1467  depName = xstrdup(Name);
1468  else {
1469  depName = xmalloc(nName + 1 + 1);
1470  (void) stpcpy(depName, Name);
1471  /* XXX re-add the pesky trailing '/' to dirnames. */
1472  depName[nName] = (tagno == RPMTAG_DIRNAMES ? '/' : '\0');
1473  depName[nName+1] = '\0';
1474  }
1475 
1476  if (depName[0] == '/' && psm->Tmires != NULL) {
1477  miRE mire;
1478  int j;
1479 
1480  /* XXX mireApply doesn't tell which pattern matched. */
1481  for (j = 0, mire = (miRE)psm->Tmires; j < psm->nTmires; j++, mire++) {
1482  const char * pattern = psm->Tpats[j];
1483  if (depName[nName-1] != '/') {
1484  size_t npattern = strlen(pattern);
1485  depName[nName] = PATT_ISDIR(pattern, npattern) ? '/' : '\0';
1486  }
1487  if (mireRegexec(mire, depName, 0) < 0)
1488  /*@innercontinue@*/ continue;
1489 
1490  /* Reset the primary retrieval key to the pattern. */
1491  depName = _free(depName);
1492  depName = xstrdup(pattern);
1493  /*@innerbreak@*/ break;
1494  }
1495  }
1496 
1497  /* Retrieve triggered header(s) by key. */
1498  mi = rpmtsInitIterator(ts, RPMTAG_TRIGGERNAME, depName, 0);
1499 
1500  nvals = argiCount(instances);
1501  vals = argiData(instances);
1502  if (nvals > 0)
1503  xx = rpmmiPrune(mi, (uint32_t *)vals, nvals, 1);
1504 
1505  prev = 0;
1506  while((triggeredH = rpmmiNext(mi)) != NULL) {
1507  instance = rpmmiInstance(mi);
1508  if (prev == instance)
1509  /*@innercontinue@*/ continue;
1510  if (handleOneTrigger(psm, fi->h, triggeredH, arg2))
1511  rc = RPMRC_FAIL;
1512  prev = instance;
1513  xx = argiAdd(&instances, -1, instance);
1514  xx = argiSort(instances, NULL);
1515  }
1516 
1517  mi = rpmmiFree(mi);
1518  }
1519 
1520  instances = argiFree(instances);
1521  depName = _free(depName);
1522  (void)rpmdsFree(ds);
1523  ds = NULL;
1524 
1525  return rc;
1526 }
1527 
1534  /*@globals rpmGlobalMacroContext, h_errno,
1535  fileSystem, internalState @*/
1536  /*@modifies psm, rpmGlobalMacroContext,
1537  fileSystem, internalState @*/
1538 {
1539  const rpmts ts = psm->ts;
1540  rpmfi fi = psm->fi;
1541  int numPackage;
1542  rpmTag tagno;
1543  rpmRC rc = RPMRC_OK;
1544 
1545  /* Select RPMTAG_NAME or RPMTAG_PROVIDENAME index for triggering. */
1546  if (_trigger_tag == 0) {
1547  const char * t = rpmExpand("%{?_trigger_tag}", NULL);
1548 /*@-mods@*/
1549  _trigger_tag = (!strcmp(t, "name") ? RPMTAG_NAME : RPMTAG_PROVIDENAME);
1550 /*@=mods@*/
1551  t = _free(t);
1552  }
1553  tagno = _trigger_tag;
1554 
1555 assert(psm->te != NULL);
1556  { const char * N = rpmteN(psm->te);
1557 assert(N != NULL);
1558  numPackage = rpmdbCountPackages(rpmtsGetRdb(ts), N);
1559  numPackage += psm->countCorrection;
1560  if (numPackage < 0)
1561  return RPMRC_NOTFOUND;
1562  }
1563 assert(fi != NULL);
1564 assert(fi->h != NULL);
1565 
1566  /* XXX Save/restore count correction. */
1567  { int countCorrection = psm->countCorrection;
1568 
1569  psm->countCorrection = 0;
1570 
1571  /* Try name/providename triggers first. */
1572  if (runTriggersLoop(psm, tagno, numPackage))
1573  rc = RPMRC_FAIL;
1574 
1575  /* If not limited to NEVRA triggers, also try file/dir path triggers. */
1576  if (tagno != RPMTAG_NAME) {
1577  int xx;
1578  /* Retrieve trigger patterns from rpmdb. */
1579  xx = rpmdbTriggerGlobs(psm);
1580 
1581  if (runTriggersLoop(psm, RPMTAG_BASENAMES, numPackage))
1582  rc = RPMRC_FAIL;
1583  if (runTriggersLoop(psm, RPMTAG_DIRNAMES, numPackage))
1584  rc = RPMRC_FAIL;
1585 
1586  psm->Tpats = argvFree(psm->Tpats);
1587  psm->Tmires = mireFreeAll((miRE)psm->Tmires, psm->nTmires);
1588  psm->nTmires = 0;
1589  }
1590 
1591  psm->countCorrection = countCorrection;
1592  }
1593 
1594  return rc;
1595 }
1596 
1603  /*@globals rpmGlobalMacroContext, h_errno,
1604  fileSystem, internalState @*/
1605  /*@modifies psm, rpmGlobalMacroContext,
1606  fileSystem, internalState @*/
1607 {
1608  HE_t Ihe = (HE_t) memset(alloca(sizeof(*Ihe)), 0, sizeof(*Ihe));
1609  const rpmts ts = psm->ts;
1610  rpmfi fi = psm->fi;
1611  rpmds triggers = NULL;
1612  rpmmi mi;
1613  ARGV_t keys = NULL;
1614  ARGI_t instances = NULL;
1615  Header sourceH = NULL;
1616  const char * Name;
1617  rpmTag tagno;
1618  rpmRC rc = RPMRC_OK;
1619  int i;
1620  int xx;
1621 
1622 assert(fi->h != NULL);
1623 
1624  /* Select RPMTAG_NAME or RPMTAG_PROVIDENAME index for triggering. */
1625  if (_trigger_tag == 0) {
1626  const char * t = rpmExpand("%{?_trigger_tag}", NULL);
1627 /*@-mods@*/
1628  _trigger_tag = (!strcmp(t, "name") ? RPMTAG_NAME : RPMTAG_PROVIDENAME);
1629 /*@=mods@*/
1630  t = _free(t);
1631  }
1632  tagno = _trigger_tag;
1633 
1634 /*@-castexpose@*/
1635  triggers = rpmdsLink(psm->triggers, "ImmedTriggers");
1636 /*@=castexpose@*/
1637  if (triggers == NULL)
1638  goto exit;
1639 
1640  Ihe->tag = RPMTAG_TRIGGERINDEX;
1641  xx = headerGet(fi->h, Ihe, 0);
1642  if (!(xx && Ihe->p.ui32p && Ihe->c)) goto exit;
1643 
1644  /* Collect primary trigger keys, expanding globs as needed. */
1645  triggers = rpmdsInit(triggers);
1646  if (triggers != NULL)
1647  while ((i = rpmdsNext(triggers)) >= 0) {
1648  evrFlags Flags = rpmdsFlags(triggers);
1649  const char * N = rpmdsN(triggers);
1650  const char * EVR = rpmdsEVR(triggers);
1651 
1652  /* Skip triggers that are not in this context. */
1653  if (!(Flags & psm->sense))
1654  continue;
1655 
1656  /* If not limited to NEVRA triggers, use file/dir index. */
1657  if (tagno != RPMTAG_NAME) {
1658  size_t nb = strlen(N);
1659  /* XXX if trigger name ends with '/', use dirnames instead. */
1660  if (N[0] == '^' || N[0] == '/')
1661  tagno = (PATT_ISDIR(N, nb)) ? RPMTAG_DIRNAMES : RPMTAG_FILEPATHS;
1662  }
1663  /* XXX For now, permit globs only in unversioned triggers. */
1664  if ((EVR == NULL || *EVR == '\0') && (N[0] == '^' || Glob_pattern_p(N, 0)))
1665  xx = rpmdbMireApply(rpmtsGetRdb(ts), tagno, N[0] == '^' ? RPMMIRE_PCRE : RPMMIRE_GLOB, N, &keys);
1666  else
1667  xx = argvAdd(&keys, N);
1668  }
1669  (void)rpmdsFree(triggers);
1670  triggers = NULL;
1671 
1672  /* For all primary keys, retrieve headers and fire triggers. */
1673  if (keys != NULL)
1674  for (i = 0; (Name = keys[i]) != NULL; i++) {
1675  unsigned prev, instance;
1676  unsigned nvals;
1677  ARGint_t vals;
1678 
1679  /* If not limited to NEVRA triggers, use file/dir index. */
1680  if (tagno != RPMTAG_NAME) {
1681  size_t nb = strlen(Name);
1682  /* XXX if trigger name ends with '/', use dirnames instead. */
1683  if (Name[0] == '^' || Name[0] == '/')
1684  tagno = PATT_ISDIR(Name, nb) ? RPMTAG_DIRNAMES : RPMTAG_FILEPATHS;
1685  }
1686 
1687  mi = rpmtsInitIterator(ts, tagno, Name, 0);
1688 
1689  /* Don't retrieve headers that have already been processed. */
1690  nvals = argiCount(instances);
1691  vals = argiData(instances);
1692  if (nvals > 0)
1693  xx = rpmmiPrune(mi, (uint32_t *)vals, nvals, 1);
1694 
1695  prev = 0;
1696  while((sourceH = rpmmiNext(mi)) != NULL) {
1697 
1698  /* Skip headers that have already been processed. */
1699  instance = rpmmiInstance(mi);
1700  if (prev == instance)
1701  /*@innercontinue@*/ continue;
1702 
1703  if (handleOneTrigger(psm, sourceH, fi->h, rpmmiCount(mi)))
1704  rc = RPMRC_FAIL;
1705 
1706  /* Mark header instance as processed. */
1707  prev = instance;
1708  xx = argiAdd(&instances, -1, instance);
1709  xx = argiSort(instances, NULL);
1710  }
1711 
1712  mi = rpmmiFree(mi);
1713  }
1714 
1715 exit:
1716  instances = argiFree(instances);
1717  keys = argvFree(keys);
1718  Ihe->p.ptr = _free(Ihe->p.ptr);
1719  return rc;
1720 }
1721 
1722 /*@observer@*/
1723 static const char * pkgStageString(pkgStage a)
1724  /*@*/
1725 {
1726  switch(a) {
1727  case PSM_UNKNOWN: return "unknown";
1728 
1729  case PSM_PKGINSTALL: return " install";
1730  case PSM_PKGERASE: return " erase";
1731  case PSM_PKGCOMMIT: return " commit";
1732  case PSM_PKGSAVE: return "repackage";
1733 
1734  case PSM_INIT: return "init";
1735  case PSM_PRE: return "pre";
1736  case PSM_PROCESS: return "process";
1737  case PSM_POST: return "post";
1738  case PSM_UNDO: return "undo";
1739  case PSM_FINI: return "fini";
1740 
1741  case PSM_CREATE: return "create";
1742  case PSM_NOTIFY: return "notify";
1743  case PSM_DESTROY: return "destroy";
1744  case PSM_COMMIT: return "commit";
1745 
1746  case PSM_CHROOT_IN: return "chrootin";
1747  case PSM_CHROOT_OUT: return "chrootout";
1748  case PSM_SCRIPT: return "script";
1749  case PSM_TRIGGERS: return "triggers";
1750  case PSM_IMMED_TRIGGERS: return "immedtriggers";
1751 
1752  case PSM_RPMIO_FLAGS: return "rpmioflags";
1753 
1754  case PSM_RPMDB_LOAD: return "rpmdbload";
1755  case PSM_RPMDB_ADD: return "rpmdbadd";
1756  case PSM_RPMDB_REMOVE: return "rpmdbremove";
1757 
1758  default: return "???";
1759  }
1760  /*@noteached@*/
1761 }
1762 
1763 void rpmpsmSetAsync(rpmpsm psm, int async)
1764 {
1765  assert(psm != NULL);
1766 #ifdef REFERENCE
1767  psm->unorderedSuccessor = async;
1768 #else
1769  if (async)
1770  F_SET(psm, UNORDERED);
1771  else
1772  F_CLR(psm, UNORDERED);
1773 #endif
1774 }
1775 
1776 rpmRC rpmpsmScriptStage(rpmpsm psm, rpmTag scriptTag, rpmTag progTag)
1777 {
1778 assert(psm != NULL);
1779  psm->scriptTag = scriptTag;
1780  psm->progTag = progTag;
1781  /* XXX other tags needed? */
1782  switch (scriptTag) {
1783  default: break;
1784  case RPMTAG_SANITYCHECK: psm->stepName = "sanitycheck"; break;
1785  case RPMTAG_VERIFYSCRIPT: psm->stepName = "verify"; break;
1786  case RPMTAG_PRETRANS: psm->stepName = "pretrans"; break;
1787  case RPMTAG_POSTTRANS: psm->stepName = "posttrans"; break;
1788  }
1789  return rpmpsmStage(psm, PSM_SCRIPT);
1790 }
1791 
1792 /*@-mustmod@*/
1793 static void rpmpsmFini(void * _psm)
1794  /*@modifies _psm @*/
1795 {
1796  rpmpsm psm = (rpmpsm) _psm;
1797 
1798 /*@-nullstate@*/
1799  psm->fi = rpmfiFree(psm->fi);
1800 #ifdef NOTYET
1801  psm->te = rpmteFree(psm->te);
1802 #else
1803  psm->te = NULL;
1804 #endif
1805 /*@-internalglobs@*/
1806  (void)rpmtsFree(psm->ts);
1807  psm->ts = NULL;
1808 /*@=internalglobs@*/
1809 
1810  psm->IPhe->p.ptr = _free(psm->IPhe->p.ptr);
1811  psm->IPhe = _free(psm->IPhe);
1812  psm->NVRA = _free(psm->NVRA);
1813  (void)rpmdsFree(psm->triggers);
1814  psm->triggers = NULL;
1815 /*@=nullstate@*/
1816 }
1817 /*@=mustmod@*/
1818 
1819 /*@unchecked@*/ /*@only@*/ /*@null@*/
1821 
1822 static rpmpsm rpmpsmGetPool(/*@null@*/ rpmioPool pool)
1823  /*@globals _psmPool, fileSystem, internalState @*/
1824  /*@modifies pool, _psmPool, fileSystem, internalState @*/
1825 {
1826  rpmpsm psm;
1827 
1828  if (_psmPool == NULL) {
1829  _psmPool = rpmioNewPool("psm", sizeof(*psm), -1, _psm_debug,
1830  NULL, NULL, rpmpsmFini);
1831  pool = _psmPool;
1832  }
1833  psm = (rpmpsm) rpmioGetPool(pool, sizeof(*psm));
1834  memset(((char *)psm)+sizeof(psm->_item), 0, sizeof(*psm)-sizeof(psm->_item));
1835  return psm;
1836 }
1837 
1839 {
1840  static const char msg[] = "rpmpsmNew";
1841  rpmpsm psm = rpmpsmGetPool(_psmPool);
1842 
1843 /*@-assignexpose -castexpose @*/
1844  if (ts) psm->ts = rpmtsLink(ts, msg);
1845 #ifdef NOTYET
1846  if (te) psm->te = rpmteLink(te, msg);
1847 #else
1848 /*@-temptrans @*/
1849  if (te) psm->te = te;
1850 /*@=temptrans @*/
1851 #endif
1852  if (fi) psm->fi = rpmfiLink(fi, msg);
1853 /*@=assignexpose =castexpose @*/
1854 
1855  psm->triggers = NULL;
1856  psm->NVRA = NULL;
1857  psm->IPhe = (HE_t) xcalloc(1, sizeof(*psm->IPhe));
1858  memset(psm->sstates, 0, sizeof(psm->sstates));
1859  memset(psm->smetrics, 0, sizeof(psm->smetrics));
1860 
1861  return rpmpsmLink(psm, msg);
1862 }
1863 
1871  /*@globals internalState @*/
1872  /*@modifies internalState @*/
1873 {
1874  HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he));
1875  rpmuint32_t val;
1876  int xx;
1877 
1878  he->tag = tag;
1879  xx = headerGet(h, he, 0);
1880  val = (xx && he->p.ui32p ? he->p.ui32p[0] : 0);
1881  he->p.ptr = _free(he->p.ptr);
1882  return val;
1883 }
1884 
1892 static int hCopyTag(Header sh, Header th, rpmTag tag)
1893  /*@globals internalState @*/
1894  /*@modifies th, internalState @*/
1895 {
1896  HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he));
1897  int xx = 1;
1898 
1899  he->tag = tag;
1900  if (headerGet(sh, he, 0) && he->c > 0)
1901  xx = headerPut(th, he, 0);
1902  he->p.ptr = _free(he->p.ptr);
1903  return 0;
1904 }
1905 
1912 static int hSaveBlinks(Header h, const struct rpmChainLink_s * blink)
1913  /*@modifies h @*/
1914 {
1915  HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he));
1916 /*@observer@*/
1917  static const char * chain_end = RPMTE_CHAIN_END;
1918  int ac;
1919  int xx = 1;
1920 
1921  /* Save forward links into header upgrade chain. */
1922  he->tag = RPMTAG_BLINKNEVRA;
1923  he->t = RPM_STRING_ARRAY_TYPE;
1924  ac = argvCount(blink->NEVRA);
1925  if (ac > 0) {
1926  he->p.argv = argvData(blink->NEVRA);
1927  he->c = ac;
1928  } else { /* XXX Add an explicit chain terminator on 1st install. */
1929  he->p.argv = &chain_end;
1930  he->c = 1;
1931  }
1932  xx = headerPut(h, he, 0);
1933 
1934  he->tag = RPMTAG_BLINKPKGID;
1935  he->t = RPM_STRING_ARRAY_TYPE;
1936  ac = argvCount(blink->Pkgid);
1937  if (ac > 0) {
1938  he->p.argv = argvData(blink->Pkgid);
1939  he->c = ac;
1940  } else { /* XXX Add an explicit chain terminator on 1st install. */
1941  he->p.argv = &chain_end;
1942  he->c = 1;
1943  }
1944  xx = headerPut(h, he, 0);
1945 
1946  he->tag = RPMTAG_BLINKHDRID;
1947  he->t = RPM_STRING_ARRAY_TYPE;
1948  ac = argvCount(blink->Hdrid);
1949  if (ac > 0) {
1950  he->p.argv = argvData(blink->Hdrid);
1951  he->c = ac;
1952  } else { /* XXX Add an explicit chain terminator on 1st install. */
1953  he->p.argv = &chain_end;
1954  he->c = 1;
1955  }
1956  xx = headerPut(h, he, 0);
1957 
1958  return 0;
1959 }
1960 
1967 static int hSaveFlinks(Header h, const struct rpmChainLink_s * flink)
1968  /*@modifies h @*/
1969 {
1970  HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he));
1971 #ifdef NOTYET
1972  /*@observer@*/
1973  static const char * chain_end = RPMTE_CHAIN_END;
1974 #endif
1975  int ac;
1976  int xx = 1;
1977 
1978  /* Save forward links into header upgrade chain. */
1979  he->tag = RPMTAG_FLINKNEVRA;
1980  he->t = RPM_STRING_ARRAY_TYPE;
1981  ac = argvCount(flink->NEVRA);
1982  if (ac > 0) {
1983  he->p.argv = argvData(flink->NEVRA);
1984  he->c = ac;
1985  }
1986 #ifdef NOTYET /* XXX is an explicit flink terminator needed? */
1987  else { /* XXX Add an explicit chain terminator on 1st install. */
1988  he->p.argv = &chain_end;
1989  he->c = 1;
1990  }
1991 #endif
1992  xx = headerPut(h, he, 0);
1993 
1994  he->tag = RPMTAG_FLINKPKGID;
1995  he->t = RPM_STRING_ARRAY_TYPE;
1996  ac = argvCount(flink->Pkgid);
1997  if (ac > 0) {
1998  he->p.argv = argvData(flink->Pkgid);
1999  he->c = ac;
2000  }
2001 #ifdef NOTYET /* XXX is an explicit flink terminator needed? */
2002  else { /* XXX Add an explicit chain terminator on 1st install. */
2003  he->p.argv = &chain_end;
2004  he->c = 1;
2005  }
2006 #endif
2007  xx = headerPut(h, he, 0);
2008 
2009  he->tag = RPMTAG_FLINKHDRID;
2010  he->t = RPM_STRING_ARRAY_TYPE;
2011  ac = argvCount(flink->Hdrid);
2012  if (ac > 0) {
2013  he->p.argv = argvData(flink->Hdrid);
2014  he->c = ac;
2015  }
2016 #ifdef NOTYET /* XXX is an explicit flink terminator needed? */
2017  else { /* XXX Add an explicit chain terminator on 1st install. */
2018  he->p.argv = &chain_end;
2019  he->c = 1;
2020  }
2021 #endif
2022  xx = headerPut(h, he, 0);
2023 
2024  return 0;
2025 }
2026 
2034 static int populateInstallHeader(const rpmts ts, const rpmte te, rpmfi fi)
2035  /*@globals h_errno, fileSystem, internalState @*/
2036  /*@modifies fi, fileSystem, internalState @*/
2037 {
2038  HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he));
2039  rpmuint32_t tscolor = rpmtsColor(ts);
2040  rpmuint32_t tecolor = rpmteColor(te);
2041  rpmuint32_t * uip;
2042  rpmuint32_t installTime[2];
2043  rpmuint32_t originTime[2];
2044  rpmuint32_t originTid[2];
2045  int xx = 1;
2046 
2047 assert(fi->h != NULL);
2048 
2049  { struct timeval tv;
2050  xx = gettimeofday(&tv, NULL);
2051  installTime[0] = (rpmuint32_t) tv.tv_sec;
2052  installTime[1] = (rpmuint32_t) tv.tv_usec;
2053  }
2054  he->tag = RPMTAG_INSTALLTIME;
2055  he->t = RPM_UINT32_TYPE;
2056  he->p.ui32p = &installTime[0];
2057  he->c = 2;
2058  xx = headerPut(fi->h, he, 0);
2059 
2060  /* Propagate the tid & time that the package was first installed. */
2061  if ((uip = rpmteOriginTime(te)) != NULL)
2062  memcpy(originTime, uip, sizeof(originTime));
2063  if (originTime[0] == 0)
2064  memcpy(originTime, installTime, sizeof(originTime));
2065  he->tag = RPMTAG_ORIGINTIME;
2066  he->t = RPM_UINT32_TYPE;
2067  he->p.ui32p = originTime;
2068  he->c = 2;
2069  xx = headerPut(fi->h, he, 0);
2070 
2071  if ((uip = rpmteOriginTid(te)) != NULL)
2072  memcpy(originTid, uip, sizeof(originTid));
2073  if (originTid[0] == 0)
2074  memcpy(originTid, ts->tid, sizeof(originTid));
2075  he->tag = RPMTAG_ORIGINTID;
2076  he->t = RPM_UINT32_TYPE;
2077  he->p.ui32p = originTid;
2078  he->c = 2;
2079  xx = headerPut(fi->h, he, 0);
2080 
2081  he->tag = RPMTAG_INSTALLCOLOR;
2082  he->t = RPM_UINT32_TYPE;
2083  he->p.ui32p = &tscolor;
2084  he->c = 1;
2085  xx = headerPut(fi->h, he, 0);
2086 
2087  /* XXX FIXME: add preferred color at install. */
2088 
2089  he->tag = RPMTAG_PACKAGECOLOR;
2090  he->t = RPM_UINT32_TYPE;
2091  he->p.ui32p = &tecolor;
2092  he->c = 1;
2093  xx = headerPut(fi->h, he, 0);
2094 
2095  /* Add the header's origin/digest/stat (i.e. URL) */
2096  { const char * fn = headerGetOrigin(fi->h);
2097  const char * digest = headerGetDigest(fi->h);
2098  struct stat * st = headerGetStatbuf(fi->h);
2099 
2100  if (fn != NULL) {
2101  he->tag = RPMTAG_PACKAGEORIGIN;
2102  he->t = RPM_STRING_TYPE;
2103  he->p.str = xstrdup(fn);
2104  he->c = 1;
2105  xx = headerPut(fi->h, he, 0);
2106  he->p.ptr = _free(he->p.ptr);
2107 
2108  if (digest != NULL) {
2109  he->tag = RPMTAG_PACKAGEDIGEST;
2110  he->t = RPM_STRING_TYPE;
2111  he->p.str = headerGetDigest(fi->h);
2112  he->c = 1;
2113  xx = headerPut(fi->h, he, 0);
2114  }
2115  if (st != NULL) {
2116 /* XXX Fstat(2) in pkgio.c should set *st. Verify st->st_mode w assert(3). */
2117 #ifndef DYING
2118  int ut = urlPath(fn, NULL);
2119  /* XXX URI is active, so avoid the lazy Stat(2) for now. */
2120  if (!(ut == URL_IS_HTTP || ut == URL_IS_HTTPS))
2121  if (st->st_mode == 0 && st->st_mtime == 0 && st->st_size == 0)
2122  xx = Stat(fn, st);
2123 #endif
2124  if (st->st_mode != 0) {
2125  he->tag = RPMTAG_PACKAGESTAT;
2126  he->t = RPM_BIN_TYPE;
2127  he->p.ptr = (void *)st;
2128  he->c = (rpmTagCount) sizeof(*st);
2129  xx = headerPut(fi->h, he, 0);
2130  }
2131  }
2132  }
2133  }
2134 
2135  /* XXX Don't clobber forward/backward upgrade chain on rollbacks */
2136  if (rpmtsType(ts) != RPMTRANS_TYPE_ROLLBACK)
2137  xx = hSaveBlinks(fi->h, &te->blink);
2138 
2139  return 0;
2140 }
2141 
2149 static int postPopulateInstallHeader(/*@unused@*/ const rpmts ts,
2150  const rpmpsm psm, rpmfi fi)
2151  /*@modifies psm, fi @*/
2152 {
2153  HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he));
2154  int fc = rpmfiFC(fi);
2155  int xx = 1;
2156 
2157  /* Add the (install) scriptlet status/metrics. */
2158  he->tag = RPMTAG_SCRIPTSTATES;
2159  he->t = RPM_UINT32_TYPE;
2160  he->p.ui32p = psm->sstates;
2161  he->c = RPMSCRIPT_MAX;
2162  xx = headerPut(fi->h, he, 0);
2163  he->tag = RPMTAG_SCRIPTMETRICS;
2164  he->t = RPM_UINT32_TYPE;
2165  he->p.ui32p = psm->smetrics;
2166  he->c = RPMSCRIPT_MAX;
2167  xx = headerPut(fi->h, he, 0);
2168 
2169  /* Add file states to install header. */
2170  if (fi->fstates != NULL && fc > 0) {
2171  he->tag = RPMTAG_FILESTATES;
2172  he->t = RPM_UINT8_TYPE;
2173  he->p.ui8p = fi->fstates;
2174  he->c = fc;
2175  xx = headerPut(fi->h, he, 0);
2176  }
2177 
2178  return 0;
2179 }
2180 
2181 #if defined(WITH_PTHREADS)
2182 static void * rpmpsmThread(void * _psm)
2183  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
2184  /*@modifies arg, rpmGlobalMacroContext, fileSystem, internalState @*/
2185 {
2186  rpmpsm psm = (rpmpsm) _psm;
2187 /*@-unqualifiedtrans@*/
2188  return ((void *) rpmpsmStage(psm, psm->nstage));
2189 /*@=unqualifiedtrans@*/
2190 }
2191 #endif
2192 
2193 static int rpmpsmNext(rpmpsm psm, pkgStage nstage)
2194  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
2195  /*@modifies psm, rpmGlobalMacroContext, fileSystem, internalState @*/
2196 {
2197  psm->nstage = nstage;
2198 #if defined(WITH_PTHREADS)
2199  if (_psm_threads)
2200  return rpmsqJoin( rpmsqThread(rpmpsmThread, psm) );
2201 #endif
2202  return rpmpsmStage(psm, psm->nstage);
2203 }
2204 
2209 /*@-nullpass@*/ /* FIX: testing null annotation for fi->h */
2211 {
2212  HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he));
2213  const rpmts ts = psm->ts;
2214  rpmuint32_t tscolor = rpmtsColor(ts);
2215  rpmfi fi = psm->fi;
2216  rpmRC rc = psm->rc;
2217  int saveerrno;
2218  int xx;
2219  int non_pre_scripts_dont_fail = 0;
2220 #if defined(RPM_VENDOR_MANDRIVA)
2221  non_pre_scripts_dont_fail = rpmExpandNumeric("%{?_legacy_compat_non_pre_scripts_dont_fail}");
2222 #endif
2223 
2224 /* XXX hackery to assert(!scareMem) in rpmfiNew. */
2225 /*@-castexpose@*/
2226 if (fi->h == NULL && fi->te && ((rpmte)fi->te)->h != NULL) fi->h = headerLink(((rpmte)fi->te)->h);
2227 /*@=castexpose@*/
2228 
2229  switch (stage) {
2230  case PSM_UNKNOWN:
2231  break;
2232  case PSM_INIT:
2233  rpmlog(RPMLOG_DEBUG, D_("%s: %s has %d files, test = %d\n"),
2234  psm->stepName, rpmteNEVR(psm->te),
2235  rpmfiFC(fi), (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST));
2236 
2237  /*
2238  * When we run scripts, we pass an argument which is the number of
2239  * versions of this package that will be installed when we are
2240  * finished.
2241  */
2242  psm->npkgs_installed = rpmdbCountPackages(rpmtsGetRdb(ts), rpmteN(psm->te));
2243  if (psm->npkgs_installed < 0) {
2244  rc = RPMRC_FAIL;
2245  break;
2246  }
2247 
2248  /* Adjust package count on rollback downgrade. */
2249 assert(psm->te != NULL);
2251  (psm->goal & ~(PSM_PKGSAVE|PSM_PKGERASE)))
2252  {
2253  if (psm->te->downgrade)
2254  psm->npkgs_installed--;
2255  }
2256 
2257  if (psm->goal == PSM_PKGINSTALL) {
2258  int fc = rpmfiFC(fi);
2259  const char * hdrid;
2260 
2261  /* Add per-transaction data to install header. */
2262  xx = populateInstallHeader(ts, psm->te, fi);
2263 
2264  psm->scriptArg = psm->npkgs_installed + 1;
2265 
2266 assert(psm->mi == NULL);
2267  hdrid = rpmteHdrid(psm->te);
2268  if (hdrid != NULL) {
2269  /* XXX should use RPMTAG_HDRID not RPMTAG_SHA1HEADER */
2270  psm->mi = rpmtsInitIterator(ts, RPMTAG_SHA1HEADER, hdrid, 0);
2271  } else {
2272  psm->mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(psm->te),0);
2274  rpmteE(psm->te));
2276  rpmteV(psm->te));
2278  rpmteR(psm->te));
2279 #ifdef RPM_VENDOR_MANDRIVA
2281  rpmteD(psm->te));
2282 #endif
2283  if (tscolor) {
2285  rpmteA(psm->te));
2286  xx = rpmmiAddPattern(psm->mi, RPMTAG_OS, RPMMIRE_STRCMP,
2287  rpmteO(psm->te));
2288  }
2289  }
2290 
2291  while ((psm->oh = rpmmiNext(psm->mi)) != NULL) {
2292  fi->record = rpmmiInstance(psm->mi);
2293  psm->oh = NULL;
2294  /*@loopbreak@*/ break;
2295  }
2296  psm->mi = rpmmiFree(psm->mi);
2297 
2298  rc = RPMRC_OK;
2299 
2300  /* XXX lazy alloc here may need to be done elsewhere. */
2301  if (fi->fstates == NULL && fc > 0) {
2302  fi->fstates = (rpmuint8_t *) xmalloc(sizeof(*fi->fstates) * fc);
2303  memset(fi->fstates, RPMFILE_STATE_NORMAL, fc);
2304  }
2305 
2306  xx = rpmtxnBegin(rpmtsGetRdb(ts), ts->txn, &psm->te->txn);
2307 
2308  if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB) break;
2309  if (fc <= 0) break;
2310 
2311  /*
2312  * Old format relocatable packages need the entire default
2313  * prefix stripped to form the cpio list, while all other packages
2314  * need the leading / stripped.
2315  */
2316  he->tag = RPMTAG_DEFAULTPREFIX;
2317  xx = headerGet(fi->h, he, 0);
2318  fi->striplen = (xx && he->p.str ? strlen(he->p.str) + 1 : 1);
2319  he->p.ptr = _free(he->p.ptr);
2320  fi->mapflags =
2322 
2323  if (headerIsEntry(fi->h, RPMTAG_ORIGBASENAMES))
2324  he->tag = RPMTAG_ORIGPATHS;
2325  else
2326  he->tag = RPMTAG_FILEPATHS;
2327  xx = headerGet(fi->h, he, 0);
2328 assert(he->p.argv != NULL);
2329  fi->apath = he->p.argv;
2330 
2331  if (fi->fuser == NULL) {
2332  he->tag = RPMTAG_FILEUSERNAME;
2333  xx = headerGet(fi->h, he, 0);
2334  fi->fuser = he->p.argv;
2335  }
2336  if (fi->fgroup == NULL) {
2337  he->tag = RPMTAG_FILEGROUPNAME;
2338  xx = headerGet(fi->h, he, 0);
2339  fi->fgroup = he->p.argv;
2340  }
2341  rc = RPMRC_OK;
2342  }
2343  if (psm->goal == PSM_PKGERASE || psm->goal == PSM_PKGSAVE) {
2344  psm->scriptArg = psm->npkgs_installed - 1;
2345 
2346  /* XXX FIXME: PSM_PKGSAVE needs to be transactionally protected. */
2347  if (psm->goal == PSM_PKGERASE)
2348  xx = rpmtxnBegin(rpmtsGetRdb(ts), ts->txn, &psm->te->txn);
2349 
2350  /* Retrieve installed header. */
2351  rc = (rpmRC) rpmpsmNext(psm, PSM_RPMDB_LOAD);
2352  if (rc == RPMRC_OK && psm->te)
2353  (void) rpmteSetHeader(psm->te, fi->h);
2354  }
2355  if (psm->goal == PSM_PKGSAVE) {
2356  /* Open output package for writing. */
2357  { char tiddn[32];
2358  const char * bfmt;
2359  const char * pkgdn;
2360  const char * pkgbn;
2361  char * pkgdn_buf;
2362 
2363  xx = snprintf(tiddn, sizeof(tiddn), "%d", rpmtsGetTid(ts));
2364  bfmt = rpmGetPath(tiddn, "/", "%{_repackage_name_fmt}", NULL);
2365  pkgbn = headerSprintf(fi->h, bfmt,
2366  NULL, rpmHeaderFormats, NULL);
2367  bfmt = _free(bfmt);
2368  psm->pkgURL = rpmGenPath("%{?_repackage_root}",
2369  "%{?_repackage_dir}",
2370  pkgbn);
2371  pkgbn = _free(pkgbn);
2372  (void) urlPath(psm->pkgURL, &psm->pkgfn);
2373  pkgdn_buf = xstrdup(psm->pkgfn);
2374 /*@-moduncon@*/
2375  pkgdn = dirname(pkgdn_buf);
2376 /*@=moduncon@*/
2377  rc = rpmMkdirPath(pkgdn, "_repackage_dir");
2378  pkgdn_buf = _free(pkgdn_buf);
2379  if (rc == RPMRC_FAIL)
2380  break;
2381  psm->fd = Fopen(psm->pkgfn, "w.fdio");
2382  if (psm->fd == NULL || Ferror(psm->fd)) {
2383  rc = RPMRC_FAIL;
2384  break;
2385  }
2386  }
2387  }
2388  break;
2389  case PSM_PRE:
2390  if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST) break;
2391 
2392 /* XXX insure that trigger index is opened before entering chroot. */
2393 #ifdef NOTYET
2394  { static int oneshot = 0;
2395  dbiIndex dbi;
2396  if (!oneshot) {
2397  dbi = dbiOpen(rpmtsGetRdb(ts), RPMTAG_TRIGGERNAME, 0);
2398  oneshot++;
2399  }
2400  }
2401 #endif
2402 
2403  /* Change root directory if requested and not already done. */
2404  rc = (rpmRC) rpmpsmNext(psm, PSM_CHROOT_IN);
2405 
2406  if (psm->goal == PSM_PKGINSTALL) {
2407  psm->scriptTag = RPMTAG_PREIN;
2408  psm->progTag = RPMTAG_PREINPROG;
2409  psm->sense = RPMSENSE_TRIGGERPREIN;
2410  psm->countCorrection = 0; /* XXX is this correct?!? */
2411 
2413 
2414  /* Run triggers in other package(s) this package sets off. */
2415  rc = (rpmRC) rpmpsmNext(psm, PSM_TRIGGERS);
2416  if (rc) break;
2417 
2418  /* Run triggers in this package other package(s) set off. */
2419  rc = (rpmRC) rpmpsmNext(psm, PSM_IMMED_TRIGGERS);
2420  if (rc) break;
2421  }
2422 
2423  if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPRE)) {
2424  rc = (rpmRC) rpmpsmNext(psm, PSM_SCRIPT);
2425  if (rc != RPMRC_OK) {
2427  _("%s: %s scriptlet failed (%d), skipping %s\n"),
2428  psm->stepName, tag2sln(psm->scriptTag), rc,
2429  rpmteNEVR(psm->te));
2430  break;
2431  }
2432  }
2433  }
2434 
2435  if (psm->goal == PSM_PKGERASE) {
2436  psm->scriptTag = RPMTAG_PREUN;
2437  psm->progTag = RPMTAG_PREUNPROG;
2438  psm->sense = RPMSENSE_TRIGGERUN;
2439  psm->countCorrection = -1;
2440 
2441  if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERUN)) {
2442  /* Run triggers in this package other package(s) set off. */
2443  rc = (rpmRC) rpmpsmNext(psm, PSM_IMMED_TRIGGERS);
2444  if(rc && !non_pre_scripts_dont_fail) break;
2445 
2446  /* Run triggers in other package(s) this package sets off. */
2447  rc = (rpmRC) rpmpsmNext(psm, PSM_TRIGGERS);
2448  if(rc && !non_pre_scripts_dont_fail) break;
2449  }
2450 
2451  if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPREUN))
2452  rc = (rpmRC) rpmpsmNext(psm, PSM_SCRIPT);
2453  }
2454  if (psm->goal == PSM_PKGSAVE) {
2455  int noArchiveSize = 0;
2456  const char * origin = NULL;
2457  const char * digest = NULL;
2458  const struct stat * st = NULL;
2459  size_t nstbytes = 0;
2460 
2461  /* Regenerate original header. */
2462  { void * uh = NULL;
2463 
2464  /* Save original header's origin/digest/stat (i.e. URL) */
2465  he->tag = RPMTAG_PACKAGEORIGIN;
2466  xx = headerGet(fi->h, he, 0);
2467  origin = he->p.str;
2468  he->tag = RPMTAG_PACKAGEDIGEST;
2469  xx = headerGet(fi->h, he, 0);
2470  if (xx && he->p.str != NULL)
2471  digest = he->p.str;
2472  he->tag = RPMTAG_PACKAGESTAT;
2473  xx = headerGet(fi->h, he, 0);
2474  if (xx && he->p.ptr != NULL && (size_t)he->c == sizeof(*st)) {
2475  st = (struct stat *) he->p.ptr;
2476  nstbytes = he->c;
2477  }
2478 
2479  /* Retrieve original header blob. */
2481  xx = headerGet(fi->h, he, 0);
2482  uh = he->p.ptr;
2483  if (xx && uh != NULL) {
2484  psm->oh = headerCopyLoad(uh);
2485  uh = _free(uh);
2486  } else {
2487  he->tag = RPMTAG_HEADERIMAGE;
2488  xx = headerGet(fi->h, he, 0);
2489  uh = he->p.ptr;
2490  if (xx && uh != NULL) {
2491  HeaderIterator hi;
2492  Header oh;
2493 
2494  /* Load the original header from the blob. */
2495  oh = headerCopyLoad(uh);
2496 
2497  /* XXX this is headerCopy w/o headerReload() */
2498  psm->oh = headerNew();
2499 
2500  for (hi = headerInit(oh);
2501  headerNext(hi, he, 0);
2502  he->p.ptr = _free(he->p.ptr))
2503  {
2504  if (he->tag == RPMTAG_ARCHIVESIZE)
2505  noArchiveSize = 1;
2506  xx = headerPut(psm->oh, he, 0);
2507  }
2508  hi = headerFini(hi);
2509 
2510  (void)headerFree(oh);
2511  oh = NULL;
2512  uh = _free(uh);
2513  } else
2514  break; /* XXX shouldn't ever happen */
2515  }
2516  }
2517 
2518  /* Retrieve type of payload compression. */
2519  /*@-nullstate@*/ /* FIX: psm->oh may be NULL */
2520  rc = (rpmRC) rpmpsmNext(psm, PSM_RPMIO_FLAGS);
2521  /*@=nullstate@*/
2522 
2523  /* Write the lead section into the package. */
2524  { static const char item[] = "Lead";
2525  const char * NEVR = rpmteNEVR(psm->te);
2526  size_t nb = rpmpkgSizeof(item, NULL);
2527 
2528  if (nb == 0)
2529  rc = RPMRC_FAIL;
2530  else {
2531  void * l = memset(alloca(nb), 0, nb);
2532  rc = rpmpkgWrite(item, psm->fd, l, &NEVR);
2533  }
2534  if (rc != RPMRC_OK) {
2535  rpmlog(RPMLOG_ERR, _("Unable to write package: %s\n"),
2536  Fstrerror(psm->fd));
2537  break;
2538  }
2539  }
2540 
2541  /* Write the signature section into the package. */
2542  /* XXX rpm-4.1 and later has archive size in signature header. */
2543  { static const char item[] = "Signature";
2544  Header sigh = headerRegenSigHeader(fi->h, noArchiveSize);
2545  /* Reallocate the signature into one contiguous region. */
2546  sigh = headerReload(sigh, RPMTAG_HEADERSIGNATURES);
2547  if (sigh == NULL) {
2548  rpmlog(RPMLOG_ERR, _("Unable to reload signature header\n"));
2549  rc = RPMRC_FAIL;
2550  break;
2551  }
2552  rc = rpmpkgWrite(item, psm->fd, sigh, NULL);
2553  (void)headerFree(sigh);
2554  sigh = NULL;
2555  if (rc != RPMRC_OK) {
2556  break;
2557  }
2558  }
2559 
2560  /* Add remove transaction id to header. */
2561  if (psm->oh != NULL)
2562  { rpmuint32_t tid = rpmtsGetTid(ts);
2563 
2564  he->tag = RPMTAG_REMOVETID;
2565  he->t = RPM_UINT32_TYPE;
2566  he->p.ui32p = &tid;
2567  he->c = 1;
2568  xx = headerPut(psm->oh, he, 0);
2569 
2570  /* Add original header's origin/digest/stat (i.e. URL) */
2571  if (origin != NULL) {
2572  he->tag = RPMTAG_PACKAGEORIGIN;
2573  he->t = RPM_STRING_TYPE;
2574  he->p.str = origin;
2575  he->c = 1;
2576  xx = headerPut(psm->oh, he, 0);
2577  origin = _free(origin);
2578  }
2579  if (digest != NULL) {
2580  he->tag = RPMTAG_PACKAGEDIGEST;
2581  he->t = RPM_STRING_TYPE;
2582  he->p.str = digest;
2583  he->c = 1;
2584  xx = headerPut(psm->oh, he, 0);
2585  digest = _free(digest);
2586  }
2587  if (st != NULL) {
2588  he->tag = RPMTAG_PACKAGESTAT;
2589  he->t = RPM_BIN_TYPE;
2590  he->p.ptr = (void *)st;
2591  he->c = (rpmTagCount)nstbytes;
2592  xx = headerPut(psm->oh, he, 0);
2593  st = _free(st);
2594  }
2595 
2596  /* Copy upgrade chain link tags. */
2597  xx = hCopyTag(fi->h, psm->oh, RPMTAG_INSTALLTID);
2598  xx = hCopyTag(fi->h, psm->oh, RPMTAG_BLINKPKGID);
2599  xx = hCopyTag(fi->h, psm->oh, RPMTAG_BLINKHDRID);
2600  xx = hCopyTag(fi->h, psm->oh, RPMTAG_BLINKNEVRA);
2601 
2602 assert(psm->te != NULL);
2603  xx = hSaveFlinks(psm->oh, &psm->te->flink);
2604  }
2605 
2606  /* Write the metadata section into the package. */
2607  { const char item[] = "Header";
2608  const char * msg = NULL;
2609  rc = rpmpkgWrite(item, psm->fd, psm->oh, &msg);
2610  if (rc != RPMRC_OK) {
2611  rpmlog(RPMLOG_ERR, "%s: %s: %s", psm->pkgfn, item,
2612  (msg && *msg ? msg : "write failed\n"));
2613  msg = _free(msg);
2614  }
2615  }
2616  }
2617  break;
2618  case PSM_PROCESS:
2619  if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST) break;
2620 
2621  if (psm->goal == PSM_PKGINSTALL) {
2622 
2623  if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB) break;
2624 
2625  /* XXX Synthesize callbacks for packages with no files. */
2626  if (rpmfiFC(fi) <= 0) {
2627  void * ptr;
2628  ptr = rpmtsNotify(ts, (rpmte)fi->te, RPMCALLBACK_INST_START, 0, 100);
2629  ptr = rpmtsNotify(ts, (rpmte)fi->te, RPMCALLBACK_INST_PROGRESS, 100, 100);
2630  break;
2631  }
2632 
2633  /* Retrieve type of payload compression. */
2634  rc = (rpmRC) rpmpsmNext(psm, PSM_RPMIO_FLAGS);
2635 
2636  if (rpmteFd((rpmte)fi->te) == NULL) { /* XXX can't happen */
2637  rc = RPMRC_FAIL;
2638  break;
2639  }
2640 
2641  /*@-nullpass@*/ /* LCL: fi->fd != NULL here. */
2642  psm->cfd = Fdopen(fdDup(Fileno(rpmteFd((rpmte)fi->te))), psm->rpmio_flags);
2643  /*@=nullpass@*/
2644  if (psm->cfd == NULL) { /* XXX can't happen */
2645  rc = RPMRC_FAIL;
2646  break;
2647  }
2648 
2649  xx = rpmtxnBegin(rpmtsGetRdb(ts), psm->te->txn, NULL);
2650 
2651  rc = (rpmRC) fsmSetup(fi->fsm, IOSM_PKGINSTALL, psm->payload_format,
2652  ts, fi, psm->cfd, NULL, &psm->failedFile);
2653  (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_UNCOMPRESS),
2654  fdstat_op(psm->cfd, FDSTAT_READ));
2655  (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DIGEST),
2656  fdstat_op(psm->cfd, FDSTAT_DIGEST));
2657  xx = fsmTeardown(fi->fsm);
2658 
2659  saveerrno = errno; /* XXX FIXME: Fclose with libio destroys errno */
2660  xx = Fclose(psm->cfd);
2661  psm->cfd = NULL;
2662  /*@-mods@*/
2663  errno = saveerrno; /* XXX FIXME: Fclose with libio destroys errno */
2664  /*@=mods@*/
2665 
2666  if (!rc)
2667  rc = (rpmRC) rpmpsmNext(psm, PSM_COMMIT);
2668 
2669  /* Commit/abort the SRPM install transaction. */
2670  /* XXX move into the PSM package state machine w PSM_COMMIT */
2671  { rpmdb db = rpmtsGetRdb(ts);
2672  rpmtxn _txn = (db ? db->db_txn : NULL);
2673  if (_txn != NULL) {
2674  if (rc)
2675  xx = rpmtxnAbort(_txn);
2676  else
2677  xx = rpmtxnCommit(_txn);
2678  db->db_txn = NULL;
2679  }
2680  }
2681 
2682  /* XXX make sure progress is closed out */
2683  psm->what = RPMCALLBACK_INST_PROGRESS;
2684  psm->amount = (fi->archiveSize ? fi->archiveSize : 100);
2685  psm->total = psm->amount;
2686  xx = rpmpsmNext(psm, PSM_NOTIFY);
2687 
2688  if (rc) {
2689  const char * msg = iosmStrerror(rc);
2691  _("unpacking of archive failed%s%s: %s\n"),
2692  (psm->failedFile != NULL ? _(" on file ") : ""),
2693  (psm->failedFile != NULL ? psm->failedFile : ""),
2694  msg);
2695  msg = _free(msg);
2696  rc = RPMRC_FAIL;
2697 
2698  /* XXX notify callback on error. */
2699  psm->what = RPMCALLBACK_UNPACK_ERROR;
2700  psm->amount = 0;
2701  psm->total = 0;
2702  xx = rpmpsmNext(psm, PSM_NOTIFY);
2703 
2704  break;
2705  }
2706  }
2707  if (psm->goal == PSM_PKGERASE) {
2708  int fc = rpmfiFC(fi);
2709 
2710  if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB) break;
2711  if (rpmtsFlags(ts) & RPMTRANS_FLAG_APPLYONLY) break;
2712 
2713  psm->what = RPMCALLBACK_UNINST_START;
2714  psm->amount = fc;
2715  psm->total = (fc ? fc : 100);
2716  xx = rpmpsmNext(psm, PSM_NOTIFY);
2717 
2718  if (fc > 0) {
2719  rc = (rpmRC) fsmSetup(fi->fsm, IOSM_PKGERASE, psm->payload_format,
2720  ts, fi, NULL, NULL, &psm->failedFile);
2721  xx = fsmTeardown(fi->fsm);
2722  }
2723 
2724  psm->what = RPMCALLBACK_UNINST_STOP;
2725  psm->amount = (fc ? fc : 100);
2726  psm->total = (fc ? fc : 100);
2727  xx = rpmpsmNext(psm, PSM_NOTIFY);
2728 
2729  }
2730  if (psm->goal == PSM_PKGSAVE) {
2731  iosmFileAction * actions = (iosmFileAction *) fi->actions;
2732  iosmFileAction action = (iosmFileAction) fi->action;
2733 
2734  fi->action = FA_COPYOUT;
2735  fi->actions = NULL;
2736 
2737  if (psm->fd == NULL) { /* XXX can't happen */
2738  rc = RPMRC_FAIL;
2739  break;
2740  }
2741  /*@-nullpass@*/ /* FIX: fdDup mey return NULL. */
2742  xx = Fflush(psm->fd);
2743  psm->cfd = Fdopen(fdDup(Fileno(psm->fd)), psm->rpmio_flags);
2744  /*@=nullpass@*/
2745  if (psm->cfd == NULL) { /* XXX can't happen */
2746  rc = RPMRC_FAIL;
2747  break;
2748  }
2749 
2750  rc = (rpmRC) fsmSetup(fi->fsm, IOSM_PKGBUILD, psm->payload_format,
2751  ts, fi, psm->cfd, NULL, &psm->failedFile);
2752  (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_COMPRESS),
2753  fdstat_op(psm->cfd, FDSTAT_WRITE));
2754  (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DIGEST),
2755  fdstat_op(psm->cfd, FDSTAT_DIGEST));
2756  xx = fsmTeardown(fi->fsm);
2757 
2758  saveerrno = errno; /* XXX FIXME: Fclose with libio destroys errno */
2759  xx = Fclose(psm->cfd);
2760  psm->cfd = NULL;
2761  /*@-mods@*/
2762  errno = saveerrno;
2763  /*@=mods@*/
2764 
2765  /* XXX make sure progress is closed out */
2766  psm->what = RPMCALLBACK_INST_PROGRESS;
2767  psm->amount = (fi->archiveSize ? fi->archiveSize : 100);
2768  psm->total = psm->amount;
2769  xx = rpmpsmNext(psm, PSM_NOTIFY);
2770 
2771  fi->action = (int) action;
2772  fi->actions = (int *) actions;
2773  }
2774  break;
2775  case PSM_POST:
2776  if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST) break;
2777 
2778  if (psm->goal == PSM_PKGINSTALL) {
2779 
2780  psm->scriptTag = RPMTAG_POSTIN;
2781  psm->progTag = RPMTAG_POSTINPROG;
2782  psm->sense = RPMSENSE_TRIGGERIN;
2783  psm->countCorrection = 0;
2784 
2785  if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPOST)) {
2786  rc = (rpmRC) rpmpsmNext(psm, PSM_SCRIPT);
2787  if(rc && !non_pre_scripts_dont_fail) break;
2788  }
2789  if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERIN)) {
2790  /* Run triggers in other package(s) this package sets off. */
2791  rc = (rpmRC) rpmpsmNext(psm, PSM_TRIGGERS);
2792  if(rc && !non_pre_scripts_dont_fail) break;
2793 
2794  /* Run triggers in this package other package(s) set off. */
2795  rc = (rpmRC) rpmpsmNext(psm, PSM_IMMED_TRIGGERS);
2796  if(rc && !non_pre_scripts_dont_fail) break;
2797  }
2798 
2799  /*
2800  * If this header has already been installed, remove it from
2801  * the database before adding the new header.
2802  */
2803  if (fi->record && !(rpmtsFlags(ts) & RPMTRANS_FLAG_APPLYONLY)) {
2804  rc = (rpmRC) rpmpsmNext(psm, PSM_RPMDB_REMOVE);
2805  if (rc) break;
2806  }
2807 
2808  /* Add scriptlet/file states to install header. */
2809  xx = postPopulateInstallHeader(ts, psm, fi);
2810 
2811  rc = (rpmRC) rpmpsmNext(psm, PSM_RPMDB_ADD);
2812  if (rc) break;
2813 
2814 #ifdef DYING
2815  if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_APPLYONLY))
2816  rc = markReplacedFiles(psm);
2817 #endif
2818 
2819  }
2820  if (psm->goal == PSM_PKGERASE) {
2821 
2822  psm->scriptTag = RPMTAG_POSTUN;
2823  psm->progTag = RPMTAG_POSTUNPROG;
2824  psm->sense = RPMSENSE_TRIGGERPOSTUN;
2825  psm->countCorrection = -1;
2826 
2827  if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPOSTUN)) {
2828  rc = (rpmRC) rpmpsmNext(psm, PSM_SCRIPT);
2829  if(rc && !non_pre_scripts_dont_fail) break;
2830  }
2831 
2833  /* Run triggers in other package(s) this package sets off. */
2834  rc = (rpmRC) rpmpsmNext(psm, PSM_TRIGGERS);
2835  if(rc && !non_pre_scripts_dont_fail) break;
2836 
2837  /* Run triggers in this package other package(s) set off. */
2838  rc = (rpmRC) rpmpsmNext(psm, PSM_IMMED_TRIGGERS);
2839  if(rc && !non_pre_scripts_dont_fail) break;
2840  }
2841 
2842  if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_APPLYONLY))
2843  rc = (rpmRC) rpmpsmNext(psm, PSM_RPMDB_REMOVE);
2844  }
2845  if (psm->goal == PSM_PKGSAVE) {
2846  }
2847 
2848  /* Restore root directory if changed. */
2849  xx = rpmpsmNext(psm, PSM_CHROOT_OUT);
2850  break;
2851  case PSM_UNDO:
2852  break;
2853  case PSM_FINI:
2854  /* Restore root directory if changed. */
2855  xx = rpmpsmNext(psm, PSM_CHROOT_OUT);
2856 
2857  if (psm->fd != NULL) {
2858  saveerrno = errno; /* XXX FIXME: Fclose with libio destroys errno */
2859  xx = Fclose(psm->fd);
2860  psm->fd = NULL;
2861  /*@-mods@*/
2862  errno = saveerrno;
2863  /*@=mods@*/
2864  }
2865 
2866  if (psm->goal == PSM_PKGSAVE) {
2867  if (!rc && ts && ts->notify == NULL) {
2868  rpmlog(RPMLOG_INFO, _("Wrote: %s\n"),
2869  (psm->pkgURL ? psm->pkgURL : "???"));
2870  }
2871  }
2872 
2873  if (rc) {
2874  const char * msg = iosmStrerror(rc);
2875  if (psm->failedFile)
2877  _("%s failed on file %s: %s\n"),
2878  psm->stepName, psm->failedFile, msg);
2879  else
2880  rpmlog(RPMLOG_ERR, _("%s failed: %s\n"),
2881  psm->stepName, msg);
2882  msg = _free(msg);
2883 
2884  /* XXX notify callback on error. */
2885  psm->what = RPMCALLBACK_CPIO_ERROR;
2886  psm->amount = 0;
2887  psm->total = 0;
2888  /*@-nullstate@*/ /* FIX: psm->fd may be NULL. */
2889  xx = rpmpsmNext(psm, PSM_NOTIFY);
2890  /*@=nullstate@*/
2891  if (psm->te->txn != NULL) {
2892  xx = rpmtxnAbort(psm->te->txn);
2893  psm->te->txn = NULL;
2894  }
2895  } else {
2896  if (psm->te->txn != NULL) {
2897  xx = rpmtxnCommit(psm->te->txn);
2898  psm->te->txn = NULL;
2899  }
2900  }
2901 
2902  if (psm->goal == PSM_PKGERASE || psm->goal == PSM_PKGSAVE) {
2903  if (psm->te != NULL)
2904  (void) rpmteSetHeader(psm->te, NULL);
2905  if (fi->h != NULL) {
2906  (void)headerFree(fi->h);
2907  fi->h = NULL;
2908  }
2909  }
2910  (void)headerFree(psm->oh);
2911  psm->oh = NULL;
2912  psm->pkgURL = _free(psm->pkgURL);
2913  psm->rpmio_flags = _free(psm->rpmio_flags);
2914  psm->payload_format = _free(psm->payload_format);
2915  psm->failedFile = _free(psm->failedFile);
2916 
2917  fi->fgroup = _free(fi->fgroup);
2918  fi->fuser = _free(fi->fuser);
2919  fi->apath = _free(fi->apath);
2920  fi->fstates = _free(fi->fstates);
2921  break;
2922 
2923  case PSM_PKGINSTALL:
2924  case PSM_PKGERASE:
2925  case PSM_PKGSAVE:
2926  psm->goal = stage;
2927  psm->rc = RPMRC_OK;
2928  psm->stepName = pkgStageString(stage);
2929 
2930  rc = (rpmRC) rpmpsmNext(psm, PSM_INIT);
2931  if (!rc) rc = (rpmRC) rpmpsmNext(psm, PSM_PRE);
2932  if (!rc) rc = (rpmRC) rpmpsmNext(psm, PSM_PROCESS);
2933  if (!rc) rc = (rpmRC) rpmpsmNext(psm, PSM_POST);
2934  xx = rpmpsmNext(psm, PSM_FINI);
2935  break;
2936  case PSM_PKGCOMMIT:
2937  break;
2938 
2939  case PSM_CREATE:
2940  break;
2941  case PSM_NOTIFY:
2942  { void * ptr;
2943 /*@-nullpass@*/ /* FIX: psm->te may be NULL */
2944  ptr = rpmtsNotify(ts, psm->te, psm->what, psm->amount, psm->total);
2945 /*@-nullpass@*/
2946  } break;
2947  case PSM_DESTROY:
2948  break;
2949  case PSM_COMMIT:
2950  if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_PKGCOMMIT)) break;
2951  if (rpmtsFlags(ts) & RPMTRANS_FLAG_APPLYONLY) break;
2952 
2953  rc = (rpmRC) fsmSetup(fi->fsm, IOSM_PKGCOMMIT, psm->payload_format,
2954  ts, fi, NULL, NULL, &psm->failedFile);
2955  xx = fsmTeardown(fi->fsm);
2956  break;
2957 
2958  case PSM_CHROOT_IN:
2959  { const char * rootDir = rpmtsRootDir(ts);
2960  /* Change root directory if requested and not already done. */
2961  if (rootDir != NULL && !(rootDir[0] == '/' && rootDir[1] == '\0')
2962  && !rpmtsChrootDone(ts) && !F_ISSET(psm, CHROOTDONE))
2963  {
2964  static int _pw_loaded = 0;
2965  static int _gr_loaded = 0;
2966 
2967  if (!_pw_loaded) {
2968  (void)getpwnam("root");
2969  endpwent();
2970  _pw_loaded++;
2971  }
2972  if (!_gr_loaded) {
2973  (void)getgrnam("root");
2974  endgrent();
2975  _gr_loaded++;
2976  }
2977 
2978  xx = Chdir("/");
2979  /*@-modobserver@*/
2980  if (rootDir != NULL && strcmp(rootDir, "/") && *rootDir == '/')
2981  rc = (rpmRC) Chroot(rootDir);
2982  /*@=modobserver@*/
2983  F_SET(psm, CHROOTDONE);
2984  (void) rpmtsSetChrootDone(ts, 1);
2985  }
2986  } break;
2987  case PSM_CHROOT_OUT:
2988  /* Restore root directory if changed. */
2989  if (F_ISSET(psm, CHROOTDONE)) {
2990  const char * rootDir = rpmtsRootDir(ts);
2991  const char * currDir = rpmtsCurrDir(ts);
2992  /*@-modobserver@*/
2993  if (rootDir != NULL && strcmp(rootDir, "/") && *rootDir == '/')
2994  rc = (rpmRC) Chroot(".");
2995  /*@=modobserver@*/
2996  F_CLR(psm, CHROOTDONE);
2997  (void) rpmtsSetChrootDone(ts, 0);
2998  if (currDir != NULL) /* XXX can't happen */
2999  xx = Chdir(currDir);
3000  }
3001  break;
3002  case PSM_SCRIPT: /* Run current package scriptlets. */
3003  /* XXX running %verifyscript/%sanitycheck doesn't have psm->te */
3004  { rpmtxn _parent = (psm && psm->te ? psm->te->txn : NULL);
3005  xx = rpmtxnBegin(rpmtsGetRdb(ts), _parent, NULL);
3006  rc = runInstScript(psm);
3007  if (rc)
3008  xx = rpmtxnAbort(rpmtsGetRdb(ts)->db_txn);
3009  else
3010  xx = rpmtxnCommit(rpmtsGetRdb(ts)->db_txn);
3011  rpmtsGetRdb(ts)->db_txn = NULL;
3012  } break;
3013  case PSM_TRIGGERS:
3014  /* Run triggers in other package(s) this package sets off. */
3015  if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST) break;
3016  rc = runTriggers(psm);
3017  break;
3018  case PSM_IMMED_TRIGGERS:
3019  /* Run triggers in this package other package(s) set off. */
3020  if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST) break;
3021  if (!F_ISSET(psm, GOTTRIGGERS)) {
3022  psm->triggers = rpmdsNew(fi->h, RPMTAG_TRIGGERNAME, 0);
3023  F_SET(psm, GOTTRIGGERS);
3024  }
3025  if (psm->triggers != NULL)
3026  rc = runImmedTriggers(psm);
3027  break;
3028 
3029  case PSM_RPMIO_FLAGS:
3030  { const char * payload_compressor = NULL;
3031  const char * payload_format = NULL;
3032  char * t;
3033 
3035  xx = headerGet(fi->h, he, 0);
3036  payload_compressor = he->p.str;
3037  if (payload_compressor == NULL)
3038  payload_compressor = xstrdup("gzip");
3039 
3040  psm->rpmio_flags = t = (char *) xmalloc(sizeof("w9.gzdio"));
3041  *t = '\0';
3042  t = stpcpy(t, ((psm->goal == PSM_PKGSAVE) ? "w9" : "r"));
3043  if (!strcmp(payload_compressor, "gzip"))
3044  t = stpcpy(t, ".gzdio");
3045  if (!strcmp(payload_compressor, "bzip2"))
3046  t = stpcpy(t, ".bzdio");
3047  if (!strcmp(payload_compressor, "lzma"))
3048  t = stpcpy(t, ".lzdio");
3049  if (!strcmp(payload_compressor, "xz"))
3050  t = stpcpy(t, ".xzdio");
3051  payload_compressor = _free(payload_compressor);
3052 
3053  he->tag = RPMTAG_PAYLOADFORMAT;
3054  xx = headerGet(fi->h, he, 0);
3055  payload_format = he->p.str;
3056  if (!xx || payload_format == NULL || !(
3057  !strcmp(payload_format, "tar") || !strcmp(payload_format, "ustar")
3058 #if defined(SUPPORT_AR_PAYLOADS)
3059  || !strcmp(payload_format, "ar")
3060 #endif
3061  ))
3062  {
3063  payload_format = _free(payload_format);
3064  payload_format = xstrdup("cpio");
3065  }
3066  psm->payload_format = _free(psm->payload_format);
3067  psm->payload_format = payload_format;
3068  rc = RPMRC_OK;
3069  } break;
3070 
3071  case PSM_RPMDB_LOAD:
3072 assert(psm->mi == NULL);
3073  psm->mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES,
3074  &fi->record, sizeof(fi->record));
3075  fi->h = rpmmiNext(psm->mi);
3076 /*@-castexpose@*/
3077  if (fi->h != NULL)
3078  fi->h = headerLink(fi->h);
3079 /*@=castexpose@*/
3080  psm->mi = rpmmiFree(psm->mi);
3081 
3082  if (fi->h != NULL) {
3083  (void) headerSetInstance(fi->h, fi->record);
3084  rc = RPMRC_OK;
3085  } else
3086  rc = RPMRC_FAIL;
3087  break;
3088  case PSM_RPMDB_ADD:
3089  if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST) break;
3090  if (rpmtsFlags(ts) & RPMTRANS_FLAG_NORPMDB) break;
3091  if (fi->isSource) break; /* XXX never add SRPM's */
3092  if (fi->h == NULL) break; /* XXX can't happen */
3093 
3094  xx = rpmtxnBegin(rpmtsGetRdb(ts), psm->te->txn, NULL);
3095 
3096  /* Add header to db, doing header check if requested */
3097  /* XXX rollback headers propagate the previous transaction id. */
3098  { rpmuint32_t tid = ((rpmtsType(ts) == RPMTRANS_TYPE_ROLLBACK)
3099  ? hLoadTID(fi->h, RPMTAG_INSTALLTID) : rpmtsGetTid(ts));
3100  (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DBADD), 0);
3101  if (!(rpmtsVSFlags(ts) & RPMVSF_NOHDRCHK))
3102  rc = (rpmRC) rpmdbAdd(rpmtsGetRdb(ts), tid, fi->h, ts);
3103  else
3104  rc = (rpmRC) rpmdbAdd(rpmtsGetRdb(ts), tid, fi->h, NULL);
3105  (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DBADD), 0);
3106 #if defined(HAVE_SYSLOG_H) && defined(RPM_VENDOR_MANDRIVA) /* log-install-remove-to-syslog */
3107  {
3108  char *s, fmt;
3109  fmt = rpmExpand("%{___NVRA}", NULL);
3110  s = headerSprintf(fi->h, fmt,
3111  rpmTagTable, rpmHeaderFormats, NULL);
3112  syslog(LOG_NOTICE, "[RPM] %s installed\n", s);
3113  fmt = _free(fmt);
3114  s = _free(s);
3115  }
3116 #endif
3117  }
3118 
3119  if (rc != RPMRC_OK) {
3120  xx = rpmtxnAbort(rpmtsGetRdb(ts)->db_txn);
3121  rpmtsGetRdb(ts)->db_txn = NULL;
3122  break;
3123  } else
3124  xx = rpmtxnCommit(rpmtsGetRdb(ts)->db_txn);
3125  rpmtsGetRdb(ts)->db_txn = NULL;
3126 
3127 assert(psm->te != NULL);
3128  /* Mark non-rollback elements as installed. */
3129  if (rpmtsType(ts) != RPMTRANS_TYPE_ROLLBACK)
3130  psm->te->installed = 1;
3131 
3132  /* Set the database instance for (possible) rollbacks. */
3133  rpmteSetDBInstance(psm->te, headerGetInstance(fi->h));
3134 
3135  break;
3136  case PSM_RPMDB_REMOVE:
3137  {
3138  if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST) break;
3139  if (rpmtsFlags(ts) & RPMTRANS_FLAG_NORPMDB) break;
3140 
3141  xx = rpmtxnBegin(rpmtsGetRdb(ts), psm->te->txn, NULL);
3142 
3143  (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DBREMOVE), 0);
3144  rc = (rpmRC) rpmdbRemove(rpmtsGetRdb(ts), rpmtsGetTid(ts), fi->record, NULL);
3145  (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DBREMOVE), 0);
3146 #if defined(HAVE_SYSLOG_H) && defined(RPM_VENDOR_MANDRIVA) /* log-install-remove-to-syslog */
3147  {
3148  char *s, fmt;
3149  fmt = rpmExpand("%{___NVRA}", NULL);
3150  s = headerSprintf(fi->h, fmt,
3151  rpmTagTable, rpmHeaderFormats, NULL);
3152  syslog(LOG_NOTICE, "[RPM] %s removed\n", s);
3153  fmt = _free(fmt);
3154  s = _free(s);
3155  }
3156 #endif
3157 
3158  if (rc != RPMRC_OK) {
3159  xx = rpmtxnAbort(rpmtsGetRdb(ts)->db_txn);
3160  rpmtsGetRdb(ts)->db_txn = NULL;
3161  break;
3162  } else
3163  xx = rpmtxnCommit(rpmtsGetRdb(ts)->db_txn);
3164  rpmtsGetRdb(ts)->db_txn = NULL;
3165 
3166  /* Forget the offset of a successfully removed header. */
3167  if (psm->te != NULL) /* XXX can't happen */
3168  psm->te->u.removed.dboffset = 0;
3169 
3170  } break;
3171 
3172  default:
3173  break;
3174 /*@i@*/ }
3175 
3176 /*@-nullstate@*/ /* FIX: psm->oh and psm->fi->h may be NULL. */
3177  return rc;
3178 /*@=nullstate@*/
3179 }
3180 /*@=nullpass@*/