rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

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@*/
56 int _psm_debug = _PSM_DEBUG;
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
184 rpmRC rpmInstallSourcePackage(rpmts ts, void * _fd,
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);
279 fi->mapflags = IOSM_MAP_PATH | IOSM_MAP_MODE | IOSM_MAP_UID | IOSM_MAP_GID;
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
460 static rpmScriptID tag2slx(rpmTag tag)
461 /*@*/
462 {
463 switch (tag) {
464 case RPMTAG_PRETRANS: return RPMSCRIPT_PRETRANS;
465 case RPMTAG_TRIGGERPREIN: return RPMSCRIPT_TRIGGERPREIN;
466 case RPMTAG_PREIN: return RPMSCRIPT_PREIN;
467 case RPMTAG_POSTIN: return RPMSCRIPT_POSTIN;
468 case RPMTAG_TRIGGERIN: return RPMSCRIPT_TRIGGERIN;
469 case RPMTAG_TRIGGERUN: return RPMSCRIPT_TRIGGERUN;
470 case RPMTAG_PREUN: return RPMSCRIPT_PREUN;
471 case RPMTAG_POSTUN: return RPMSCRIPT_POSTUN;
472 case RPMTAG_POSTTRANS: return RPMSCRIPT_POSTTRANS;
473 case RPMTAG_TRIGGERPOSTUN: return RPMSCRIPT_TRIGGERPOSTUN;
474 case RPMTAG_VERIFYSCRIPT: return RPMSCRIPT_VERIFY;
475 case RPMTAG_SANITYCHECK: return RPMSCRIPT_SANITYCHECK;
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
497 rpmlog(RPMLOG_DEBUG,
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)
660 *ssp |= (RPMSCRIPT_STATE_LUA|RPMSCRIPT_STATE_EXEC);
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)
789 *ssp = RPMSCRIPT_STATE_UNKNOWN;
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)
816 rpmlog(RPMLOG_DEBUG,
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)) {
831 rpmlog(RPMLOG_DEBUG,
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
840 rpmlog(RPMLOG_DEBUG,
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;
973 rpmlog(RPMLOG_DEBUG,
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) {
1070 rpmlog(RPMLOG_ERR,
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));
1080 rpmlog(RPMLOG_ERR,
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));
1086 rpmlog(RPMLOG_ERR,
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
1116 static rpmRC runInstScript(rpmpsm psm)
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@*/
1161 static rpmTag _trigger_tag;
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
1224 Phe->tag = RPMTAG_TRIGGERSCRIPTPROG;
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;
1346 int xx = rpmdbMireApply(rpmtsGetRdb(ts), RPMTAG_TRIGGERNAME,
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
1461 static rpmRC runTriggers(rpmpsm psm)
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
1516 psm->countCorrection = countCorrection;
1517 }
1518
1519 return rc;
1520 }
1521
1527 static rpmRC runImmedTriggers(rpmpsm psm)
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] == '/')
1586 ? RPMTAG_DIRNAMES : RPMTAG_FILEPATHS;
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] == '/')
1609 ? RPMTAG_DIRNAMES : RPMTAG_FILEPATHS;
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@*/
1716 rpmioPool _psmPool;
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
1732 rpmpsm rpmpsmNew(rpmts ts, rpmte te, rpmfi fi)
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
1763 static rpmuint32_t hLoadTID(Header h, rpmTag tag)
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 */
2091 rpmRC rpmpsmStage(rpmpsm psm, pkgStage stage)
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 */
2119 psm->npkgs_installed = rpmdbCountPackages(rpmtsGetRdb(ts), rpmteN(psm->te));
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);
2127 if (rpmtsType(ts) == RPMTRANS_TYPE_AUTOROLLBACK &&
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);
2150 xx = rpmmiAddPattern(psm->mi, RPMTAG_EPOCH, RPMMIRE_STRCMP,
2151 rpmteE(psm->te));
2152 xx = rpmmiAddPattern(psm->mi, RPMTAG_VERSION, RPMMIRE_STRCMP,
2153 rpmteV(psm->te));
2154 xx = rpmmiAddPattern(psm->mi, RPMTAG_RELEASE, RPMMIRE_STRCMP,
2155 rpmteR(psm->te));
2156 #ifdef RPM_VENDOR_MANDRIVA
2157 xx = rpmmiAddPattern(psm->mi, RPMTAG_DISTEPOCH, RPMMIRE_STRCMP,
2158 rpmteD(psm->te));
2159 #endif
2160 if (tscolor) {
2161 xx = rpmmiAddPattern(psm->mi,RPMTAG_ARCH, RPMMIRE_STRCMP,
2162 rpmteA(psm->te));
2163 xx = rpmmiAddPattern(psm->mi, RPMTAG_OS, RPMMIRE_STRCMP,
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 =
2196 IOSM_MAP_PATH | IOSM_MAP_MODE | IOSM_MAP_UID | IOSM_MAP_GID | (fi->mapflags & IOSM_SBIT_CHECK);
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
2289 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERPREIN)) {
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) {
2303 rpmlog(RPMLOG_ERR,
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. */
2357 he->tag = RPMTAG_HEADERIMMUTABLE;
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 */
2546 psm->what = RPMCALLBACK_INST_PROGRESS;
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);
2553 rpmlog(RPMLOG_ERR,
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. */
2562 psm->what = RPMCALLBACK_UNPACK_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
2576 psm->what = RPMCALLBACK_UNINST_START;
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
2587 psm->what = RPMCALLBACK_UNINST_STOP;
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 */
2629 psm->what = RPMCALLBACK_INST_PROGRESS;
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
2693 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERPOSTUN)) {
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)
2737 rpmlog(RPMLOG_ERR,
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. */
2746 psm->what = RPMCALLBACK_CPIO_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
2886 he->tag = RPMTAG_PAYLOADCOMPRESSOR;
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);
2925 psm->mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES,
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@*/