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