rpm 5.2.1

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

- File List
- Globals

fsm.c
Go to the documentation of this file.
1
6 #include "system.h"
7
8 #include <rpmio_internal.h> /* XXX urlPath, fdGetCpioPos */
9 #include <rpmcb.h> /* XXX fnpyKey */
10 #include <rpmtag.h>
11 #include <rpmtypes.h>
12
13 #define _RPMFI_INTERNAL
14 #include "rpmfi.h"
15
16 #define _IOSM_INTERNAL
17 #include <fsm.h>
18 #define fsmUNSAFE fsmStage
19
20 #if defined(SUPPORT_AR_PAYLOADS)
21 #include "ar.h"
22 #endif
23 #include "cpio.h"
24 #include "tar.h"
25
26 #define _USE_RPMTE
27 #if defined(_USE_RPMTE)
28 #include "rpmte.h"
29 #endif
30 #include "rpmts.h"
31 #include "rpmsq.h"
32
33 #include "ugid.h" /* XXX unameToUid() and gnameToGid() */
34
35 #include "debug.h"
36
37 /*@access FD_t @*/ /* XXX void ptr args */
38 /*@access FSMI_t @*/
39 /*@access IOSM_t @*/
40 /*@access IOSMI_t @*/
41
42 /*@access rpmfi @*/
43
44 /*@access rpmsx @*/ /* XXX cast */
45 /*@access rpmte @*/ /* XXX cast */
46 /*@access rpmts @*/ /* XXX cast */
47
48 #define alloca_strdup(_s) strcpy(alloca(strlen(_s)+1), (_s))
49
50 #define _FSM_DEBUG 0
51 /*@unchecked@*/
52 int _fsm_debug = _FSM_DEBUG;
53
54 /*@-exportheadervar@*/
55 /*@unchecked@*/
56 int _fsm_threads = 0;
57 /*@=exportheadervar@*/
58
64 static rpmts fsmGetTs(const IOSM_t fsm)
65 /*@*/
66 {
67 const FSMI_t iter = fsm->iter;
68 /*@-compdef -refcounttrans -retexpose -usereleased @*/
69 return (iter ? iter->ts : NULL);
70 /*@=compdef =refcounttrans =retexpose =usereleased @*/
71 }
72
78 static rpmfi fsmGetFi(const IOSM_t fsm)
79 /*@*/
80 {
81 const FSMI_t iter = fsm->iter;
82 /*@-compdef -refcounttrans -retexpose -usereleased @*/
83 return (iter ? iter->fi : NULL);
84 /*@=compdef =refcounttrans =retexpose =usereleased @*/
85 }
86
87 #define SUFFIX_RPMORIG ".rpmorig"
88 #define SUFFIX_RPMSAVE ".rpmsave"
89 #define SUFFIX_RPMNEW ".rpmnew"
90
99 static /*@only@*//*@null@*/
100 const char * fsmFsPath(/*@special@*/ /*@null@*/ const IOSM_t fsm,
101 /*@null@*/ const struct stat * st,
102 /*@null@*/ const char * subdir,
103 /*@null@*/ const char * suffix)
104 /*@uses fsm->dirName, fsm->baseName */
105 /*@*/
106 {
107 const char * s = NULL;
108
109 if (fsm) {
110 char * t;
111 int nb;
112 nb = strlen(fsm->dirName) +
113 (st && !S_ISDIR(st->st_mode) ? (subdir ? strlen(subdir) : 0) : 0) +
114 (st && !S_ISDIR(st->st_mode) ? (suffix ? strlen(suffix) : 0) : 0) +
115 strlen(fsm->baseName) + 1;
116 s = t = xmalloc(nb);
117 t = stpcpy(t, fsm->dirName);
118 if (st && !S_ISDIR(st->st_mode))
119 if (subdir) t = stpcpy(t, subdir);
120 t = stpcpy(t, fsm->baseName);
121 if (st && !S_ISDIR(st->st_mode))
122 if (suffix) t = stpcpy(t, suffix);
123 }
124 return s;
125 }
126
132 static /*@null@*/ void * mapFreeIterator(/*@only@*//*@null@*/ void * p)
133 /*@globals fileSystem @*/
134 /*@modifies fileSystem @*/
135 {
136 FSMI_t iter = p;
137 if (iter) {
138 iter->fi = rpmfiUnlink(iter->fi, "mapIterator");
139 /*@-internalglobs@*/ /* XXX rpmswExit() */
140 (void)rpmtsFree(iter->ts);
141 iter->ts = NULL;
142 /*@=internalglobs@*/
143 }
144 return _free(p);
145 }
146
153 static void *
154 mapInitIterator(rpmfi fi, int reverse)
155 /*@modifies fi @*/
156 {
157 FSMI_t iter = NULL;
158
159 iter = xcalloc(1, sizeof(*iter));
160 /*@-assignexpose -castexpose @*/
161 iter->fi = rpmfiLink(fi, "mapIterator");
162 /*@=assignexpose =castexpose @*/
163 iter->reverse = reverse;
164 iter->i = (iter->reverse ? (fi->fc - 1) : 0);
165 iter->isave = iter->i;
166 return iter;
167 }
168
174 static int mapNextIterator(/*@null@*/ void * a)
175 /*@*/
176 {
177 FSMI_t iter = a;
178 int i = -1;
179
180 if (iter) {
181 /*@-onlytrans@*/
182 const rpmfi fi = iter->fi;
183 /*@=onlytrans@*/
184 if (iter->reverse) {
185 if (iter->i >= 0) i = iter->i--;
186 } else {
187 if (iter->i < (int)fi->fc) i = iter->i++;
188 }
189 iter->isave = i;
190 }
191 return i;
192 }
193
196 static int cpioStrCmp(const void * a, const void * b)
197 /*@*/
198 {
199 const char * aurl = *(const char **)a;
200 const char * burl = *(const char **)b;
201 const char * afn = NULL;
202 const char * bfn = NULL;
203
204 (void) urlPath(aurl, &afn);
205 (void) urlPath(burl, &bfn);
206
207 #ifdef VERY_OLD_BUGGY_RPM_PACKAGES
208 /* XXX Some rpm-2.4 packages from 1997 have basename only in payloads. */
209 if (strchr(afn, '/') == NULL)
210 bfn = strrchr(bfn, '/') + 1;
211 #endif
212
213 /* Match rpm-4.0 payloads with ./ prefixes. */
214 if (afn[0] == '.' && afn[1] == '/') afn += 2;
215 if (bfn[0] == '.' && bfn[1] == '/') bfn += 2;
216
217 /* If either path is absolute, make it relative to '/'. */
218 if (afn[0] == '/') afn += 1;
219 if (bfn[0] == '/') bfn += 1;
220
221 return strcmp(afn, bfn);
222 }
223
230 static int mapFind(/*@null@*/ FSMI_t iter, const char * fsmPath)
231 /*@modifies iter @*/
232 {
233 int ix = -1;
234
235 if (iter) {
236 /*@-onlytrans@*/
237 const rpmfi fi = iter->fi;
238 /*@=onlytrans@*/
239 size_t fc = rpmfiFC(fi);
240 if (fi && fc > 0 && fi->apath && fsmPath && *fsmPath) {
241 const char ** p = NULL;
242
243 if (fi->apath != NULL)
244 p = bsearch(&fsmPath, fi->apath, fc, sizeof(fsmPath),
245 cpioStrCmp);
246 if (p) {
247 iter->i = p - fi->apath;
248 ix = mapNextIterator(iter);
249 }
250 }
251 }
252 return ix;
253 }
254
258 typedef struct dnli_s {
259 rpmfi fi;
260 /*@only@*/ /*@null@*/
261 char * active;
262 int reverse;
263 int isave;
264 int i;
265 } * DNLI_t;
266
272 static /*@null@*/ void * dnlFreeIterator(/*@only@*//*@null@*/ const void * a)
273 /*@modifies a @*/
274 {
275 if (a) {
276 DNLI_t dnli = (void *)a;
277 if (dnli->active) free(dnli->active);
278 }
279 return _free(a);
280 }
281
284 static inline int dnlCount(/*@null@*/ const DNLI_t dnli)
285 /*@*/
286 {
287 return (int) (dnli ? dnli->fi->dc : 0);
288 }
289
292 static inline int dnlIndex(/*@null@*/ const DNLI_t dnli)
293 /*@*/
294 {
295 return (dnli ? dnli->isave : -1);
296 }
297
304 /*@-usereleased@*/
305 static /*@only@*/ /*@null@*/
306 void * dnlInitIterator(/*@special@*/ const IOSM_t fsm,
307 int reverse)
308 /*@uses fsm->iter @*/
309 /*@*/
310 {
311 rpmfi fi = fsmGetFi(fsm);
312 const char * dnl;
313 DNLI_t dnli;
314 int i, j;
315
316 if (fi == NULL)
317 return NULL;
318 dnli = xcalloc(1, sizeof(*dnli));
319 dnli->fi = fi;
320 dnli->reverse = reverse;
321 dnli->i = (int) (reverse ? fi->dc : 0);
322
323 if (fi->dc) {
324 dnli->active = xcalloc(fi->dc, sizeof(*dnli->active));
325
326 /* Identify parent directories not skipped. */
327 if ((fi = rpmfiInit(fi, 0)) != NULL)
328 while ((i = rpmfiNext(fi)) >= 0) {
329 if (!iosmFileActionSkipped(fi->actions[i])) dnli->active[fi->dil[i]] = 1;
330 }
331
332 /* Exclude parent directories that are explicitly included. */
333 if ((fi = rpmfiInit(fi, 0)) != NULL)
334 while ((i = rpmfiNext(fi)) >= 0) {
335 rpmuint32_t dil;
336 size_t dnlen, bnlen;
337
338 if (!S_ISDIR(fi->fmodes[i]))
339 continue;
340
341 dil = fi->dil[i];
342 dnlen = strlen(fi->dnl[dil]);
343 bnlen = strlen(fi->bnl[i]);
344
345 for (j = 0; j < (int)fi->dc; j++) {
346 size_t jlen;
347
348 if (!dnli->active[j] || j == (int)dil)
349 /*@innercontinue@*/ continue;
350 (void) urlPath(fi->dnl[j], &dnl);
351 jlen = strlen(dnl);
352 if (jlen != (dnlen+bnlen+1))
353 /*@innercontinue@*/ continue;
354 if (strncmp(dnl, fi->dnl[dil], dnlen))
355 /*@innercontinue@*/ continue;
356 if (strncmp(dnl+dnlen, fi->bnl[i], bnlen))
357 /*@innercontinue@*/ continue;
358 if (dnl[dnlen+bnlen] != '/' || dnl[dnlen+bnlen+1] != '\0')
359 /*@innercontinue@*/ continue;
360 /* This directory is included in the package. */
361 dnli->active[j] = 0;
362 /*@innerbreak@*/ break;
363 }
364 }
365
366 /* Print only once per package. */
367 if (!reverse) {
368 j = 0;
369 for (i = 0; i < (int)fi->dc; i++) {
370 if (!dnli->active[i]) continue;
371 if (j == 0) {
372 j = 1;
373 rpmlog(RPMLOG_DEBUG,
374 D_("========== Directories not explicitly included in package:\n"));
375 }
376 (void) urlPath(fi->dnl[i], &dnl);
377 rpmlog(RPMLOG_DEBUG, "%10d %s\n", i, dnl);
378 }
379 if (j)
380 rpmlog(RPMLOG_DEBUG, "==========\n");
381 }
382 }
383 return dnli;
384 }
385 /*@=usereleased@*/
386
392 static /*@observer@*/ /*@null@*/
393 const char * dnlNextIterator(/*@null@*/ DNLI_t dnli)
394 /*@modifies dnli @*/
395 {
396 const char * dn = NULL;
397
398 if (dnli) {
399 rpmfi fi = dnli->fi;
400 int i = -1;
401
402 if (dnli->active)
403 do {
404 i = (!dnli->reverse ? dnli->i++ : --dnli->i);
405 } while (i >= 0 && i < (int)fi->dc && !dnli->active[i]);
406
407 if (i >= 0 && i < (int)fi->dc)
408 dn = fi->dnl[i];
409 else
410 i = -1;
411 dnli->isave = i;
412 }
413 return dn;
414 }
415
416 #if defined(WITH_PTHREADS)
417 static void * fsmThread(void * arg)
418 /*@globals h_errno, fileSystem, internalState @*/
419 /*@modifies arg, fileSystem, internalState @*/
420 {
421 IOSM_t fsm = arg;
422 /*@-unqualifiedtrans@*/
423 return ((void *) ((long)fsmStage(fsm, fsm->nstage)));
424 /*@=unqualifiedtrans@*/
425 }
426 #endif
427
428 int fsmNext(IOSM_t fsm, iosmFileStage nstage)
429 /*@globals h_errno, fileSystem, internalState @*/
430 /*@modifies fsm, fileSystem, internalState @*/
431 {
432 fsm->nstage = nstage;
433 #if defined(WITH_PTHREADS)
434 if (fsm->multithreaded)
435 return rpmsqJoin( rpmsqThread(fsmThread, fsm) );
436 #endif
437 return fsmStage(fsm, fsm->nstage);
438 }
439
445 static int saveHardLink(/*@special@*/ /*@partial@*/ IOSM_t fsm)
446 /*@uses fsm->links, fsm->ix, fsm->sb, fsm->goal, fsm->nsuffix @*/
447 /*@defines fsm->li @*/
448 /*@releases fsm->path @*/
449 /*@globals h_errno, fileSystem, internalState @*/
450 /*@modifies fsm, fileSystem, internalState @*/
451 {
452 struct stat * st = &fsm->sb;
453 int rc = 0;
454 int ix = -1;
455 int j;
456
457 /* Find hard link set. */
458 for (fsm->li = fsm->links; fsm->li; fsm->li = fsm->li->next) {
459 if (fsm->li->sb.st_ino == st->st_ino && fsm->li->sb.st_dev == st->st_dev)
460 break;
461 }
462
463 /* New hard link encountered, add new link to set. */
464 if (fsm->li == NULL) {
465 fsm->li = xcalloc(1, sizeof(*fsm->li));
466 fsm->li->next = NULL;
467 fsm->li->sb = *st; /* structure assignment */
468 fsm->li->nlink = (int) st->st_nlink;
469 fsm->li->linkIndex = fsm->ix;
470 fsm->li->createdPath = -1;
471
472 fsm->li->filex = xcalloc(st->st_nlink, sizeof(fsm->li->filex[0]));
473 memset(fsm->li->filex, -1, (st->st_nlink * sizeof(fsm->li->filex[0])));
474 fsm->li->nsuffix = xcalloc(st->st_nlink, sizeof(*fsm->li->nsuffix));
475
476 if (fsm->goal == IOSM_PKGBUILD)
477 fsm->li->linksLeft = (int) st->st_nlink;
478 if (fsm->goal == IOSM_PKGINSTALL)
479 fsm->li->linksLeft = 0;
480
481 /*@-kepttrans@*/
482 fsm->li->next = fsm->links;
483 /*@=kepttrans@*/
484 fsm->links = fsm->li;
485 }
486
487 if (fsm->goal == IOSM_PKGBUILD) --fsm->li->linksLeft;
488 fsm->li->filex[fsm->li->linksLeft] = fsm->ix;
489 /*@-observertrans -dependenttrans@*/
490 fsm->li->nsuffix[fsm->li->linksLeft] = fsm->nsuffix;
491 /*@=observertrans =dependenttrans@*/
492 if (fsm->goal == IOSM_PKGINSTALL) fsm->li->linksLeft++;
493
494 if (fsm->goal == IOSM_PKGBUILD)
495 return (fsm->li->linksLeft > 0);
496
497 if (fsm->goal != IOSM_PKGINSTALL)
498 return 0;
499
500 if (!(st->st_size || fsm->li->linksLeft == (int) st->st_nlink))
501 return 1;
502
503 /* Here come the bits, time to choose a non-skipped file name. */
504 { rpmfi fi = fsmGetFi(fsm);
505
506 for (j = fsm->li->linksLeft - 1; j >= 0; j--) {
507 ix = fsm->li->filex[j];
508 if (ix < 0 || iosmFileActionSkipped(fi->actions[ix]))
509 continue;
510 break;
511 }
512 }
513
514 /* Are all links skipped or not encountered yet? */
515 if (ix < 0 || j < 0)
516 return 1; /* XXX W2DO? */
517
518 /* Save the non-skipped file name and map index. */
519 fsm->li->linkIndex = j;
520 fsm->path = _free(fsm->path);
521 fsm->ix = ix;
522 rc = fsmNext(fsm, IOSM_MAP);
523 return rc;
524 }
525
531 static /*@null@*/ void * freeHardLink(/*@only@*/ /*@null@*/ struct hardLink_s * li)
532 /*@modifies li @*/
533 {
534 if (li) {
535 li->nsuffix = _free(li->nsuffix); /* XXX elements are shared */
536 li->filex = _free(li->filex);
537 }
538 return _free(li);
539 }
540
541 IOSM_t newFSM(void)
542 {
543 IOSM_t fsm = xcalloc(1, sizeof(*fsm));
544 return fsm;
545 }
546
547 IOSM_t freeFSM(IOSM_t fsm)
548 {
549 if (fsm) {
550 fsm->path = _free(fsm->path);
551 while ((fsm->li = fsm->links) != NULL) {
552 fsm->links = fsm->li->next;
553 fsm->li->next = NULL;
554 fsm->li = freeHardLink(fsm->li);
555 }
556 fsm->dnlx = _free(fsm->dnlx);
557 fsm->ldn = _free(fsm->ldn);
558 fsm->iter = mapFreeIterator(fsm->iter);
559 }
560 return _free(fsm);
561 }
562
563 #if defined(SUPPORT_AR_PAYLOADS)
564 static int arSetup(IOSM_t fsm, rpmfi fi)
565 /*@modifies fsm @*/
566 {
567 const char * path;
568 char * t;
569 size_t lmtablen = 0;
570 size_t nb;
571
572 /* Calculate size of ar(1) long member table. */
573 if ((fi = rpmfiInit(fi, 0)) != NULL)
574 while (rpmfiNext(fi) >= 0) {
575 #ifdef NOTYET
576 if (fi->apath) {
577 const char * apath = NULL;
578 (void) urlPath(fi->apath[ix], &apath);
579 path = apath + fi->striplen;
580 } else
581 #endif
582 path = rpmfiBN(fi);
583 if ((nb = strlen(path)) < 15)
584 continue;
585 lmtablen += nb + 1; /* trailing \n */
586 }
587
588 /* Anything to do? */
589 if (lmtablen == 0)
590 return 0;
591
592 /* Create and load ar(1) long member table. */
593 fsm->lmtab = t = xmalloc(lmtablen + 1); /* trailing \0 */
594 fsm->lmtablen = lmtablen;
595 fsm->lmtaboff = 0;
596 if ((fi = rpmfiInit(fi, 0)) != NULL)
597 while (rpmfiNext(fi) >= 0) {
598 #ifdef NOTYET
599 if (fi->apath) {
600 const char * apath = NULL;
601 (void) urlPath(fi->apath[ix], &apath);
602 path = apath + fi->striplen;
603 } else
604 #endif
605 path = rpmfiBN(fi);
606 if ((nb = strlen(path)) < 15)
607 continue;
608 t = stpcpy(t, path);
609 *t++ = '\n';
610 }
611 *t = '\0';
612
613 return 0;
614 }
615 #endif
616
617 int fsmSetup(void * _fsm, iosmFileStage goal, const char * afmt,
618 const void * _ts, const void * _fi, FD_t cfd,
619 unsigned int * archiveSize, const char ** failedFile)
620 {
621 IOSM_t fsm = _fsm;
622 /*@-castexpose@*/
623 const rpmts ts = (const rpmts) _ts;
624 const rpmfi fi = (const rpmfi) _fi;
625 /*@=castexpose@*/
626 #if defined(_USE_RPMTE)
627 int reverse = (rpmteType(fi->te) == TR_REMOVED && fi->action != FA_COPYOUT);
628 int adding = (rpmteType(fi->te) == TR_ADDED);
629 #else
630 int reverse = 0; /* XXX HACK: devise alternative means */
631 int adding = 1; /* XXX HACK: devise alternative means */
632 #endif
633 size_t pos = 0;
634 int rc, ec = 0;
635
636 fsm->debug = _fsm_debug;
637 fsm->multithreaded = _fsm_threads;
638 fsm->adding = adding;
639
640 /*@+voidabstract -nullpass@*/
641 if (fsm->debug < 0)
642 fprintf(stderr, "--> fsmSetup(%p, 0x%x, \"%s\", %p, %p, %p, %p, %p)\n", fsm, goal, afmt, (void *)ts, fi, cfd, archiveSize, failedFile);
643 /*@=voidabstract =nullpass@*/
644
645 _iosmNext = &fsmNext;
646 if (fsm->headerRead == NULL) {
647 if (afmt != NULL && (!strcmp(afmt, "tar") || !strcmp(afmt, "ustar"))) {
648 if (fsm->debug < 0)
649 fprintf(stderr, "\ttar vectors set\n");
650 fsm->headerRead = &tarHeaderRead;
651 fsm->headerWrite = &tarHeaderWrite;
652 fsm->trailerWrite = &tarTrailerWrite;
653 fsm->blksize = TAR_BLOCK_SIZE;
654 } else
655 #if defined(SUPPORT_AR_PAYLOADS)
656 if (afmt != NULL && !strcmp(afmt, "ar")) {
657 if (fsm->debug < 0)
658 fprintf(stderr, "\tar vectors set\n");
659 fsm->headerRead = &arHeaderRead;
660 fsm->headerWrite = &arHeaderWrite;
661 fsm->trailerWrite = &arTrailerWrite;
662 fsm->blksize = 2;
663 if (goal == IOSM_PKGBUILD || goal == IOSM_PKGERASE)
664 (void) arSetup(fsm, fi);
665 } else
666 #endif
667 {
668 if (fsm->debug < 0)
669 fprintf(stderr, "\tcpio vectors set\n");
670 fsm->headerRead = &cpioHeaderRead;
671 fsm->headerWrite = &cpioHeaderWrite;
672 fsm->trailerWrite = &cpioTrailerWrite;
673 fsm->blksize = 4;
674 }
675 }
676
677 fsm->goal = goal;
678 if (cfd != NULL) {
679 /*@-assignexpose -castexpose @*/
680 fsm->cfd = fdLink(cfd, "persist (fsm)");
681 /*@=assignexpose =castexpose @*/
682 pos = fdGetCpioPos(fsm->cfd);
683 fdSetCpioPos(fsm->cfd, 0);
684 }
685 /*@-mods@*/ /* LCL: avoid void * _ts/_fi annotations for now. */
686 fsm->iter = mapInitIterator(fi, reverse);
687 /*@-assignexpose -castexpose @*/
688 fsm->iter->ts = rpmtsLink(ts, "mapIterator");
689 /*@=assignexpose =castexpose @*/
690 fsm->nofcontexts = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONTEXTS);
691 /*@=mods@*/
692 fsm->nofdigests =
693 (ts != NULL && !(rpmtsFlags(ts) & RPMTRANS_FLAG_NOFDIGESTS))
694 ? 0 : 1;
695 #define _tsmask (RPMTRANS_FLAG_PKGCOMMIT | RPMTRANS_FLAG_COMMIT)
696 fsm->commit = ((ts && (rpmtsFlags(ts) & _tsmask) &&
697 fsm->goal != IOSM_PKGCOMMIT) ? 0 : 1);
698 #undef _tsmask
699
700 if (fsm->goal == IOSM_PKGINSTALL || fsm->goal == IOSM_PKGBUILD) {
701 void * ptr;
702 fi->archivePos = 0;
703 ptr = rpmtsNotify(ts, fi->te,
704 RPMCALLBACK_INST_START, fi->archivePos, fi->archiveSize);
705 }
706
707 /*@-assignexpose@*/
708 fsm->archiveSize = archiveSize;
709 if (fsm->archiveSize)
710 *fsm->archiveSize = 0;
711 fsm->failedFile = failedFile;
712 if (fsm->failedFile)
713 *fsm->failedFile = NULL;
714 /*@=assignexpose@*/
715
716 memset(fsm->sufbuf, 0, sizeof(fsm->sufbuf));
717 if (fsm->goal == IOSM_PKGINSTALL) {
718 if (ts && rpmtsGetTid(ts) != (rpmuint32_t)-1)
719 sprintf(fsm->sufbuf, ";%08x", (unsigned)rpmtsGetTid(ts));
720 }
721
722 ec = fsm->rc = 0;
723 /*@-mods@*/ /* LCL: avoid void * _fsm annotation for now. */
724 rc = fsmUNSAFE(fsm, IOSM_CREATE);
725 /*@=mods@*/
726 if (rc && !ec) ec = rc;
727
728 /*@-mods@*/ /* LCL: avoid void * _fsm annotation for now. */
729 rc = fsmUNSAFE(fsm, fsm->goal);
730 /*@=mods@*/
731 if (rc && !ec) ec = rc;
732
733 if (fsm->archiveSize && ec == 0)
734 *fsm->archiveSize = (fdGetCpioPos(fsm->cfd) - pos);
735
736 /*@-nullstate@*/ /* FIX: *fsm->failedFile may be NULL */
737 return ec;
738 /*@=nullstate@*/
739 }
740
741 int fsmTeardown(void * _fsm)
742 {
743 IOSM_t fsm = _fsm;
744 int rc = fsm->rc;
745
746 if (fsm->debug < 0)
747 fprintf(stderr, "--> fsmTeardown(%p)\n", fsm);
748 if (!rc)
749 rc = fsmUNSAFE(fsm, IOSM_DESTROY);
750
751 (void) rpmswAdd(rpmtsOp(fsmGetTs(fsm), RPMTS_OP_DIGEST),
752 &fsm->op_digest);
753
754 fsm->lmtab = _free(fsm->lmtab);
755 (void)rpmtsFree(fsm->iter->ts);
756 fsm->iter->ts = NULL;
757 fsm->iter = mapFreeIterator(fsm->iter);
758 if (fsm->cfd != NULL) {
759 /*@-refcounttrans@*/ /* FIX: XfdFree annotation */
760 fsm->cfd = fdFree(fsm->cfd, "persist (fsm)");
761 /*@=refcounttrans@*/
762 fsm->cfd = NULL;
763 }
764 fsm->failedFile = NULL;
765 return rc;
766 }
767
768 /*
769 * Set file security context (if not disabled).
770 * @param fsm file state machine data
771 * @return 0 always
772 */
773 static int fsmMapFContext(IOSM_t fsm)
774 /*@modifies fsm @*/
775 {
776 fsm->fcontext = NULL;
777 if (!fsm->nofcontexts) {
778 security_context_t scon = NULL;
779 /*@-moduncon@*/
780 int xx = matchpathcon(fsm->path, fsm->sb.st_mode, &scon);
781 /*@=moduncon@*/
782
783 if (!xx && scon != NULL)
784 fsm->fcontext = scon;
785 #ifdef DYING /* XXX SELinux file contexts not set from package content. */
786 else {
787 rpmfi fi = fsmGetFi(fsm);
788 int i = fsm->ix;
789
790 /* Get file security context from package. */
791 if (fi && i >= 0 && i < (int)fi->fc)
792 fsm->fcontext = (fi->fcontexts ? fi->fcontexts[i] : NULL);
793 }
794 #endif
795 }
796 return 0;
797 }
798
799 int fsmMapPath(IOSM_t fsm)
800 {
801 rpmfi fi = fsmGetFi(fsm); /* XXX const except for fstates */
802 int teAdding = fsm->adding;
803 int rc = 0;
804 int i = fsm->ix;
805
806 fsm->osuffix = NULL;
807 fsm->nsuffix = NULL;
808 fsm->astriplen = 0;
809 fsm->action = FA_UNKNOWN;
810 fsm->mapFlags = fi->mapflags;
811
812 if (fi && i >= 0 && i < (int)fi->fc) {
813
814 fsm->astriplen = fi->astriplen;
815 fsm->action = (fi->actions ? fi->actions[i] : fi->action);
816 fsm->fflags = (fi->fflags ? fi->fflags[i] : fi->flags);
817 fsm->mapFlags = (fi->fmapflags ? fi->fmapflags[i] : fi->mapflags);
818
819 /* src rpms have simple base name in payload. */
820 fsm->dirName = fi->dnl[fi->dil[i]];
821 fsm->baseName = fi->bnl[i];
822
823 switch (fsm->action) {
824 case FA_SKIP:
825 break;
826 case FA_UNKNOWN:
827 break;
828
829 case FA_COPYOUT:
830 break;
831 case FA_COPYIN:
832 case FA_CREATE:
833 assert(teAdding);
834 break;
835
836 case FA_SKIPNSTATE:
837 if (fi->fstates && teAdding)
838 fi->fstates[i] = RPMFILE_STATE_NOTINSTALLED;
839 break;
840
841 case FA_SKIPNETSHARED:
842 if (fi->fstates && teAdding)
843 fi->fstates[i] = RPMFILE_STATE_NETSHARED;
844 break;
845
846 case FA_SKIPCOLOR:
847 if (fi->fstates && teAdding)
848 fi->fstates[i] = RPMFILE_STATE_WRONGCOLOR;
849 break;
850
851 case FA_BACKUP:
852 if (!(fsm->fflags & RPMFILE_GHOST)) /* XXX Don't if %ghost file. */
853 fsm->osuffix = (teAdding ? SUFFIX_RPMORIG : SUFFIX_RPMSAVE);
854 break;
855
856 case FA_ALTNAME:
857 assert(teAdding);
858 if (!(fsm->fflags & RPMFILE_GHOST)) /* XXX Don't if %ghost file. */
859 fsm->nsuffix = SUFFIX_RPMNEW;
860 break;
861
862 case FA_SAVE:
863 assert(teAdding);
864 if (!(fsm->fflags & RPMFILE_GHOST)) /* XXX Don't if %ghost file. */
865 fsm->osuffix = SUFFIX_RPMSAVE;
866 break;
867 case FA_ERASE:
868 #if 0 /* XXX is this a genhdlist fix? */
869 assert(rpmteType(fi->te) == TR_REMOVED);
870 #endif
871 /*
872 * XXX TODO: %ghost probably shouldn't be removed, but that changes
873 * legacy rpm behavior.
874 */
875 break;
876 default:
877 break;
878 }
879
880 if ((fsm->mapFlags & IOSM_MAP_PATH) || fsm->nsuffix) {
881 const struct stat * st = &fsm->sb;
882 fsm->path = _free(fsm->path);
883 fsm->path = fsmFsPath(fsm, st, fsm->subdir,
884 (fsm->suffix ? fsm->suffix : fsm->nsuffix));
885 }
886 }
887 return rc;
888 }
889
890 int fsmMapAttrs(IOSM_t fsm)
891 {
892 struct stat * st = &fsm->sb;
893 rpmfi fi = fsmGetFi(fsm);
894 int i = fsm->ix;
895
896 if (fi && i >= 0 && i < (int) fi->fc) {
897 mode_t perms = (S_ISDIR(st->st_mode) ? fi->dperms : fi->fperms);
898 mode_t finalMode = (fi->fmodes ? (mode_t)fi->fmodes[i] : perms);
899 dev_t finalRdev = (dev_t)(fi->frdevs ? fi->frdevs[i] : 0);
900 rpmuint32_t finalMtime = (fi->fmtimes ? fi->fmtimes[i] : 0);
901 uid_t uid = fi->uid;
902 gid_t gid = fi->gid;
903
904 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* no-owner-group-on-srpm-install */
905 /* Make sure OpenPKG/Mandriva RPM does not try to set file owner/group on files during
906 installation of _source_ RPMs. Instead, let it use the current
907 run-time owner/group, because most of the time the owner/group in
908 the source RPM (which is the owner/group of the files as staying on
909 the package author system) is not existing on the target system, of
910 course. */
911 #endif
912 if (fi->fuser && unameToUid(fi->fuser[i], &uid)) {
913 #if defined(RPM_VENDOR_OPENPKG) ||defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* no-owner-group-on-srpm-install */
914 if (!fi->isSource) {
915 #endif
916 if (fsm->goal == IOSM_PKGINSTALL)
917 rpmlog(RPMLOG_WARNING,
918 _("user %s does not exist - using root\n"), fi->fuser[i]);
919 uid = 0;
920 finalMode &= ~S_ISUID; /* turn off suid bit */
921 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* no-owner-group-on-srpm-install */
922 }
923 #endif
924 }
925
926 if (fi->fgroup && gnameToGid(fi->fgroup[i], &gid)) {
927 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* no-owner-group-on-srpm-install */
928 if (!fi->isSource) {
929 #endif
930 if (fsm->goal == IOSM_PKGINSTALL)
931 rpmlog(RPMLOG_WARNING,
932 _("group %s does not exist - using root\n"), fi->fgroup[i]);
933 gid = 0;
934 finalMode &= ~S_ISGID; /* turn off sgid bit */
935 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* no-owner-group-on-srpm-install */
936 }
937 #endif
938 }
939
940 if (fsm->mapFlags & IOSM_MAP_MODE)
941 st->st_mode = (st->st_mode & S_IFMT) | (finalMode & ~S_IFMT);
942 if (fsm->mapFlags & IOSM_MAP_TYPE) {
943 st->st_mode = (st->st_mode & ~S_IFMT) | (finalMode & S_IFMT);
944 if ((S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
945 && st->st_nlink == 0)
946 st->st_nlink = 1;
947 st->st_rdev = finalRdev;
948 st->st_mtime = finalMtime;
949 }
950 if (fsm->mapFlags & IOSM_MAP_UID)
951 st->st_uid = uid;
952 if (fsm->mapFlags & IOSM_MAP_GID)
953 st->st_gid = gid;
954
955 /*
956 * Set file digest (if not disabled).
957 */
958 if (!fsm->nofdigests) {
959 fsm->fdigestalgo = fi->digestalgo;
960 fsm->fdigest = (fi->fdigests ? fi->fdigests[i] : NULL);
961 fsm->digestlen = fi->digestlen;
962 fsm->digest = (fi->digests ? (fi->digests + (fsm->digestlen * i)) : NULL);
963 } else {
964 fsm->fdigestalgo = 0;
965 fsm->fdigest = NULL;
966 fsm->digestlen = 0;
967 fsm->digest = NULL;
968 }
969 }
970 return 0;
971 }
972
978 /*@-compdef@*/
979 static int extractRegular(/*@special@*/ IOSM_t fsm)
980 /*@uses fsm->fdigest, fsm->digest, fsm->sb, fsm->wfd @*/
981 /*@globals h_errno, fileSystem, internalState @*/
982 /*@modifies fsm, fileSystem, internalState @*/
983 {
984 const struct stat * st = &fsm->sb;
985 size_t left = (size_t) st->st_size;
986 int rc = 0;
987 int xx;
988
989 rc = fsmNext(fsm, IOSM_WOPEN);
990 if (rc)
991 goto exit;
992
993 if (st->st_size > 0 && (fsm->fdigest != NULL || fsm->digest != NULL))
994 fdInitDigest(fsm->wfd, fsm->fdigestalgo, 0);
995
996 while (left) {
997
998 fsm->wrlen = (left > fsm->wrsize ? fsm->wrsize : left);
999 rc = fsmNext(fsm, IOSM_DREAD);
1000 if (rc)
1001 goto exit;
1002
1003 rc = fsmNext(fsm, IOSM_WRITE);
1004 if (rc)
1005 goto exit;
1006
1007 left -= fsm->wrnb;
1008
1009 /* Notify iff progress, completion is done elsewhere */
1010 if (!rc && left)
1011 (void) fsmNext(fsm, IOSM_NOTIFY);
1012 }
1013
1014 xx = fsync(Fileno(fsm->wfd));
1015
1016 if (st->st_size > 0 && (fsm->fdigest || fsm->digest)) {
1017 void * digest = NULL;
1018 int asAscii = (fsm->digest == NULL ? 1 : 0);
1019
1020 (void) Fflush(fsm->wfd);
1021 fdFiniDigest(fsm->wfd, fsm->fdigestalgo, &digest, NULL, asAscii);
1022
1023 if (digest == NULL) {
1024 rc = IOSMERR_DIGEST_MISMATCH;
1025 goto exit;
1026 }
1027
1028 if (fsm->digest != NULL) {
1029 if (memcmp(digest, fsm->digest, fsm->digestlen))
1030 rc = IOSMERR_DIGEST_MISMATCH;
1031 } else {
1032 if (strcmp(digest, fsm->fdigest))
1033 rc = IOSMERR_DIGEST_MISMATCH;
1034 }
1035 digest = _free(digest);
1036 }
1037
1038 exit:
1039 (void) fsmNext(fsm, IOSM_WCLOSE);
1040 return rc;
1041 }
1042 /*@=compdef@*/
1043
1050 /*@-compdef -compmempass@*/
1051 static int writeFile(/*@special@*/ /*@partial@*/ IOSM_t fsm, int writeData)
1052 /*@uses fsm->path, fsm->opath, fsm->sb, fsm->osb, fsm->cfd @*/
1053 /*@globals h_errno, fileSystem, internalState @*/
1054 /*@modifies fsm, fileSystem, internalState @*/
1055 {
1056 const char * path = fsm->path;
1057 const char * opath = fsm->opath;
1058 struct stat * st = &fsm->sb;
1059 struct stat * ost = &fsm->osb;
1060 size_t left;
1061 int xx;
1062 int rc;
1063
1064 st->st_size = (writeData ? ost->st_size : 0);
1065
1066 if (S_ISDIR(st->st_mode)) {
1067 st->st_size = 0;
1068 } else if (S_ISLNK(st->st_mode)) {
1069 /*
1070 * While linux puts the size of a symlink in the st_size field,
1071 * I don't think that's a specified standard.
1072 */
1073 /* XXX NUL terminated result in fsm->rdbuf, len in fsm->rdnb. */
1074 rc = fsmUNSAFE(fsm, IOSM_READLINK);
1075 if (rc) goto exit;
1076 st->st_size = fsm->rdnb;
1077 fsm->lpath = xstrdup(fsm->rdbuf); /* XXX save readlink return. */
1078 }
1079
1080 if (fsm->mapFlags & IOSM_MAP_ABSOLUTE) {
1081 size_t nb= strlen(fsm->dirName) + strlen(fsm->baseName) + sizeof(".");
1082 char * t = alloca(nb);
1083 *t = '\0';
1084 fsm->path = t;
1085 if (fsm->mapFlags & IOSM_MAP_ADDDOT)
1086 *t++ = '.';
1087 t = stpcpy( stpcpy(t, fsm->dirName), fsm->baseName);
1088 } else if (fsm->mapFlags & IOSM_MAP_PATH) {
1089 rpmfi fi = fsmGetFi(fsm);
1090 if (fi->apath) {
1091 const char * apath = NULL;
1092 (void) urlPath(fi->apath[fsm->ix], &apath);
1093 fsm->path = apath + fi->striplen;
1094 } else
1095 fsm->path = fi->bnl[fsm->ix];
1096 }
1097
1098 rc = fsmNext(fsm, IOSM_HWRITE);
1099 fsm->path = path;
1100 if (rc) goto exit;
1101
1102 if (writeData && S_ISREG(st->st_mode)) {
1103 #if defined(HAVE_MMAP)
1104 char * rdbuf = NULL;
1105 void * mapped = (void *)-1;
1106 size_t nmapped = 0;
1107 /* XXX 128 Mb resource cap for top(1) scrutiny, MADV_DONTNEED better. */
1108 int use_mmap = (st->st_size <= 0x07ffffff);
1109 #endif
1110
1111 rc = fsmNext(fsm, IOSM_ROPEN);
1112 if (rc) goto exit;
1113
1114 /* XXX unbuffered mmap generates *lots* of fdio debugging */
1115 #if defined(HAVE_MMAP)
1116 if (use_mmap) {
1117 mapped = mmap(NULL, st->st_size, PROT_READ, MAP_SHARED, Fileno(fsm->rfd), 0);
1118 if (mapped != (void *)-1) {
1119 rdbuf = fsm->rdbuf;
1120 fsm->rdbuf = (char *) mapped;
1121 fsm->rdlen = nmapped = st->st_size;
1122 #if defined(HAVE_MADVISE) && defined(MADV_DONTNEED)
1123 xx = madvise(mapped, nmapped, MADV_DONTNEED);
1124 #endif
1125 }
1126 }
1127 #endif
1128
1129 left = st->st_size;
1130
1131 while (left) {
1132 #if defined(HAVE_MMAP)
1133 if (mapped != (void *)-1) {
1134 fsm->rdnb = nmapped;
1135 } else
1136 #endif
1137 {
1138 fsm->rdlen = (left > fsm->rdsize ? fsm->rdsize : left),
1139 rc = fsmNext(fsm, IOSM_READ);
1140 if (rc) goto exit;
1141 }
1142
1143 /* XXX DWRITE uses rdnb for I/O length. */
1144 rc = fsmNext(fsm, IOSM_DWRITE);
1145 if (rc) goto exit;
1146
1147 left -= fsm->wrnb;
1148 }
1149
1150 #if defined(HAVE_MMAP)
1151 if (mapped != (void *)-1) {
1152 /* XXX splint misses size_t 2nd arg. */
1153 /*@i@*/ xx = msync(mapped, nmapped, MS_ASYNC);
1154 #if defined(HAVE_MADVISE) && defined(MADV_DONTNEED)
1155 xx = madvise(mapped, nmapped, MADV_DONTNEED);
1156 #endif
1157 xx = munmap(mapped, nmapped);
1158 fsm->rdbuf = rdbuf;
1159 } else
1160 #endif
1161 xx = fsync(Fileno(fsm->rfd));
1162
1163 }
1164
1165 rc = fsmNext(fsm, IOSM_PAD);
1166 if (rc) goto exit;
1167
1168 rc = 0;
1169
1170 exit:
1171 if (fsm->rfd != NULL)
1172 (void) fsmNext(fsm, IOSM_RCLOSE);
1173 /*@-dependenttrans@*/
1174 fsm->opath = opath;
1175 fsm->path = path;
1176 /*@=dependenttrans@*/
1177 return rc;
1178 }
1179 /*@=compdef =compmempass@*/
1180
1186 static int writeLinkedFile(/*@special@*/ /*@partial@*/ IOSM_t fsm)
1187 /*@uses fsm->path, fsm->nsuffix, fsm->ix, fsm->li, fsm->failedFile @*/
1188 /*@globals h_errno, fileSystem, internalState @*/
1189 /*@modifies fsm, fileSystem, internalState @*/
1190 {
1191 const char * path = fsm->path;
1192 const char * lpath = fsm->lpath;
1193 const char * nsuffix = fsm->nsuffix;
1194 int iterIndex = fsm->ix;
1195 int ec = 0;
1196 int rc;
1197 int i;
1198 const char * linkpath = NULL;
1199 int firstfile = 1;
1200
1201 fsm->path = NULL;
1202 fsm->lpath = NULL;
1203 fsm->nsuffix = NULL;
1204 fsm->ix = -1;
1205
1206 for (i = fsm->li->nlink - 1; i >= 0; i--) {
1207
1208 if (fsm->li->filex[i] < 0) continue;
1209
1210 fsm->ix = fsm->li->filex[i];
1211 /*@-compdef@*/
1212 rc = fsmNext(fsm, IOSM_MAP);
1213 /*@=compdef@*/
1214
1215 /* XXX tar and cpio have to do things differently. */
1216 if (fsm->headerWrite == tarHeaderWrite) {
1217 if (firstfile) {
1218 const char * apath = NULL;
1219 char *t;
1220 (void) urlPath(fsm->path, &apath);
1221 /* Remove the buildroot prefix. */
1222 t = xmalloc(sizeof(".") + strlen(apath + fsm->astriplen));
1223 (void) stpcpy( stpcpy(t, "."), apath + fsm->astriplen);
1224 linkpath = t;
1225 firstfile = 0;
1226 } else
1227 fsm->lpath = linkpath;
1228
1229 /* Write data after first link for tar. */
1230 rc = writeFile(fsm, (fsm->lpath == NULL));
1231 } else {
1232 /* Write data after last link for cpio. */
1233 rc = writeFile(fsm, (i == 0));
1234 }
1235 if (fsm->failedFile && rc != 0 && *fsm->failedFile == NULL) {
1236 ec = rc;
1237 *fsm->failedFile = xstrdup(fsm->path);
1238 }
1239
1240 fsm->path = _free(fsm->path);
1241 fsm->li->filex[i] = -1;
1242 }
1243
1244 /*@-dependenttrans@*/
1245 linkpath = _free(linkpath);
1246 /*@=dependenttrans@*/
1247 fsm->ix = iterIndex;
1248 fsm->nsuffix = nsuffix;
1249 fsm->lpath = lpath;
1250 fsm->path = path;
1251 return ec;
1252 }
1253
1259 /*@-compdef@*/
1260 static int fsmMakeLinks(/*@special@*/ /*@partial@*/ IOSM_t fsm)
1261 /*@uses fsm->path, fsm->opath, fsm->nsuffix, fsm->ix, fsm->li @*/
1262 /*@globals h_errno, fileSystem, internalState @*/
1263 /*@modifies fsm, fileSystem, internalState @*/
1264 {
1265 const char * path = fsm->path;
1266 const char * opath = fsm->opath;
1267 const char * nsuffix = fsm->nsuffix;
1268 int iterIndex = fsm->ix;
1269 int ec = 0;
1270 int rc;
1271 int i;
1272
1273 fsm->path = NULL;
1274 fsm->opath = NULL;
1275 fsm->nsuffix = NULL;
1276 fsm->ix = -1;
1277
1278 fsm->ix = fsm->li->filex[fsm->li->createdPath];
1279 rc = fsmNext(fsm, IOSM_MAP);
1280 fsm->opath = fsm->path;
1281 fsm->path = NULL;
1282 for (i = 0; i < fsm->li->nlink; i++) {
1283 if (fsm->li->filex[i] < 0) continue;
1284 if (fsm->li->createdPath == i) continue;
1285
1286 fsm->ix = fsm->li->filex[i];
1287 fsm->path = _free(fsm->path);
1288 rc = fsmNext(fsm, IOSM_MAP);
1289 if (iosmFileActionSkipped(fsm->action)) continue;
1290
1291 rc = fsmUNSAFE(fsm, IOSM_VERIFY);
1292 if (!rc) continue;
1293 if (!(rc == IOSMERR_ENOENT)) break;
1294
1295 /* XXX link(fsm->opath, fsm->path) */
1296 rc = fsmNext(fsm, IOSM_LINK);
1297 if (fsm->failedFile && rc != 0 && *fsm->failedFile == NULL) {
1298 ec = rc;
1299 *fsm->failedFile = xstrdup(fsm->path);
1300 }
1301
1302 fsm->li->linksLeft--;
1303 }
1304 fsm->path = _free(fsm->path);
1305 fsm->opath = _free(fsm->opath);
1306
1307 fsm->ix = iterIndex;
1308 fsm->nsuffix = nsuffix;
1309 fsm->path = path;
1310 fsm->opath = opath;
1311 return ec;
1312 }
1313 /*@=compdef@*/
1314
1320 /*@-compdef@*/
1321 static int fsmCommitLinks(/*@special@*/ /*@partial@*/ IOSM_t fsm)
1322 /*@uses fsm->path, fsm->nsuffix, fsm->ix, fsm->sb,
1323 fsm->li, fsm->links @*/
1324 /*@globals h_errno, fileSystem, internalState @*/
1325 /*@modifies fsm, fileSystem, internalState @*/
1326 {
1327 const char * path = fsm->path;
1328 const char * nsuffix = fsm->nsuffix;
1329 int iterIndex = fsm->ix;
1330 struct stat * st = &fsm->sb;
1331 int rc = 0;
1332 int i;
1333
1334 fsm->path = NULL;
1335 fsm->nsuffix = NULL;
1336 fsm->ix = -1;
1337
1338 for (fsm->li = fsm->links; fsm->li; fsm->li = fsm->li->next) {
1339 if (fsm->li->sb.st_ino == st->st_ino && fsm->li->sb.st_dev == st->st_dev)
1340 break;
1341 }
1342
1343 for (i = 0; i < fsm->li->nlink; i++) {
1344 if (fsm->li->filex[i] < 0) continue;
1345 fsm->ix = fsm->li->filex[i];
1346 rc = fsmNext(fsm, IOSM_MAP);
1347 if (!iosmFileActionSkipped(fsm->action))
1348 rc = fsmNext(fsm, IOSM_COMMIT);
1349 fsm->path = _free(fsm->path);
1350 fsm->li->filex[i] = -1;
1351 }
1352
1353 fsm->ix = iterIndex;
1354 fsm->nsuffix = nsuffix;
1355 fsm->path = path;
1356 return rc;
1357 }
1358 /*@=compdef@*/
1359
1365 static int fsmRmdirs(/*@special@*/ /*@partial@*/ IOSM_t fsm)
1366 /*@uses fsm->path, fsm->dnlx, fsm->ldn, fsm->rdbuf, fsm->iter @*/
1367 /*@globals h_errno, fileSystem, internalState @*/
1368 /*@modifies fsm, fileSystem, internalState @*/
1369 {
1370 const char * path = fsm->path;
1371 void * dnli = dnlInitIterator(fsm, 1);
1372 char * dn = fsm->rdbuf;
1373 int dc = dnlCount(dnli);
1374 int rc = 0;
1375
1376 fsm->path = NULL;
1377 dn[0] = '\0';
1378 /*@-observertrans -dependenttrans@*/
1379 if (fsm->ldn != NULL && fsm->dnlx != NULL)
1380 while ((fsm->path = dnlNextIterator(dnli)) != NULL) {
1381 size_t dnlen = strlen(fsm->path);
1382 char * te;
1383
1384 dc = dnlIndex(dnli);
1385 if (fsm->dnlx[dc] < 1 || (size_t)fsm->dnlx[dc] >= dnlen)
1386 continue;
1387
1388 /* Copy to avoid const on fsm->path. */
1389 te = stpcpy(dn, fsm->path) - 1;
1390 fsm->path = dn;
1391
1392 /* Remove generated directories. */
1393 /*@-usereleased@*/ /* LCL: te used after release? */
1394 do {
1395 if (*te == '/') {
1396 *te = '\0';
1397 /*@-compdef@*/
1398 rc = fsmNext(fsm, IOSM_RMDIR);
1399 /*@=compdef@*/
1400 *te = '/';
1401 }
1402 if (rc)
1403 /*@innerbreak@*/ break;
1404 te--;
1405 } while ((te - fsm->path) > fsm->dnlx[dc]);
1406 /*@=usereleased@*/
1407 }
1408 dnli = dnlFreeIterator(dnli);
1409 /*@=observertrans =dependenttrans@*/
1410
1411 fsm->path = path;
1412 return rc;
1413 }
1414
1420 static int fsmMkdirs(/*@special@*/ /*@partial@*/ IOSM_t fsm)
1421 /*@uses fsm->path, fsm->sb, fsm->osb, fsm->rdbuf, fsm->iter,
1422 fsm->ldn, fsm->ldnlen, fsm->ldnalloc @*/
1423 /*@defines fsm->dnlx, fsm->ldn @*/
1424 /*@globals h_errno, fileSystem, internalState @*/
1425 /*@modifies fsm, fileSystem, internalState @*/
1426 {
1427 struct stat * st = &fsm->sb;
1428 struct stat * ost = &fsm->osb;
1429 const char * path = fsm->path;
1430 mode_t st_mode = st->st_mode;
1431 void * dnli = dnlInitIterator(fsm, 0);
1432 char * dn = fsm->rdbuf;
1433 int dc = dnlCount(dnli);
1434 int rc = 0;
1435 size_t i;
1436
1437 fsm->path = NULL;
1438
1439 dn[0] = '\0';
1440 fsm->dnlx = (dc ? xcalloc(dc, sizeof(*fsm->dnlx)) : NULL);
1441 /*@-observertrans -dependenttrans@*/
1442 if (fsm->dnlx != NULL)
1443 while ((fsm->path = dnlNextIterator(dnli)) != NULL) {
1444 size_t dnlen = strlen(fsm->path);
1445 char * te;
1446
1447 dc = dnlIndex(dnli);
1448 if (dc < 0) continue;
1449 fsm->dnlx[dc] = (unsigned short) dnlen;
1450 if (dnlen <= 1)
1451 continue;
1452
1453 /*@-compdef -nullpass@*/ /* FIX: fsm->ldn not defined ??? */
1454 if (dnlen <= fsm->ldnlen && !strcmp(fsm->path, fsm->ldn))
1455 continue;
1456 /*@=compdef =nullpass@*/
1457
1458 /* Copy to avoid const on fsm->path. */
1459 (void) stpcpy(dn, fsm->path);
1460 fsm->path = dn;
1461
1462 /* Assume '/' directory exists, "mkdir -p" for others if non-existent */
1463 (void) urlPath(dn, (const char **)&te);
1464 for (i = 1, te++; *te != '\0'; te++, i++) {
1465 if (*te != '/')
1466 /*@innercontinue@*/ continue;
1467
1468 *te = '\0';
1469
1470 /* Already validated? */
1471 /*@-usedef -compdef -nullpass -nullderef@*/
1472 if (i < fsm->ldnlen &&
1473 (fsm->ldn[i] == '/' || fsm->ldn[i] == '\0') &&
1474 !strncmp(fsm->path, fsm->ldn, i))
1475 {
1476 *te = '/';
1477 /* Move pre-existing path marker forward. */
1478 fsm->dnlx[dc] = (te - dn);
1479 /*@innercontinue@*/ continue;
1480 }
1481 /*@=usedef =compdef =nullpass =nullderef@*/
1482
1483 /* Validate next component of path. */
1484 rc = fsmUNSAFE(fsm, IOSM_LSTAT);
1485 *te = '/';
1486
1487 /* Directory already exists? */
1488 if (rc == 0 && S_ISDIR(ost->st_mode)) {
1489 /* Move pre-existing path marker forward. */
1490 fsm->dnlx[dc] = (te - dn);
1491 } else if (rc == IOSMERR_ENOENT) {
1492 rpmfi fi = fsmGetFi(fsm);
1493 *te = '\0';
1494 st->st_mode = S_IFDIR | (fi->dperms & 07777);
1495 rc = fsmNext(fsm, IOSM_MKDIR);
1496 if (!rc) {
1497 security_context_t scon = NULL;
1498 /* XXX FIXME? only new dir will have context set. */
1499 /* Get file security context from patterns. */
1500 /*@-moduncon@*/
1501 if (!fsm->nofcontexts
1502 && !matchpathcon(fsm->path, st->st_mode, &scon)
1503 && scon != NULL)
1504 /*@=moduncon@*/
1505 {
1506 fsm->fcontext = scon;
1507 rc = fsmNext(fsm, IOSM_LSETFCON);
1508 } else
1509 fsm->fcontext = NULL;
1510 if (fsm->fcontext == NULL)
1511 rpmlog(RPMLOG_DEBUG,
1512 D_("%s directory created with perms %04o, no context.\n"),
1513 fsm->path, (unsigned)(st->st_mode & 07777));
1514 else {
1515 rpmlog(RPMLOG_DEBUG,
1516 D_("%s directory created with perms %04o, context %s.\n"),
1517 fsm->path, (unsigned)(st->st_mode & 07777),
1518 fsm->fcontext);
1519 fsm->fcontext = NULL;
1520 scon = _free(scon);
1521 }
1522 }
1523 *te = '/';
1524 }
1525 if (rc)
1526 /*@innerbreak@*/ break;
1527 }
1528 if (rc) break;
1529
1530 /* Save last validated path. */
1531 /*@-compdef@*/ /* FIX: ldn/path annotations ? */
1532 if (fsm->ldnalloc < (dnlen + 1)) {
1533 fsm->ldnalloc = dnlen + 100;
1534 fsm->ldn = xrealloc(fsm->ldn, fsm->ldnalloc);
1535 }
1536 if (fsm->ldn != NULL) { /* XXX can't happen */
1537 strcpy(fsm->ldn, fsm->path);
1538 fsm->ldnlen = dnlen;
1539 }
1540 /*@=compdef@*/
1541 }
1542 dnli = dnlFreeIterator(dnli);
1543 /*@=observertrans =dependenttrans@*/
1544
1545 fsm->path = path;
1546 st->st_mode = st_mode; /* XXX restore st->st_mode */
1547 /*@-compdef@*/ /* FIX: ldn/path annotations ? */
1548 return rc;
1549 /*@=compdef@*/
1550 }
1551
1552 #ifdef NOTYET
1553
1558 static int fsmStat(/*@special@*/ /*@partial@*/ IOSM_t fsm)
1559 /*@globals fileSystem, internalState @*/
1560 /*@modifies fsm, fileSystem, internalState @*/
1561 {
1562 int rc = 0;
1563
1564 if (fsm->path != NULL) {
1565 int saveernno = errno;
1566 rc = fsmUNSAFE(fsm, (!(fsm->mapFlags & IOSM_FOLLOW_SYMLINKS)
1567 ? IOSM_LSTAT : IOSM_STAT));
1568 if (rc == IOSMERR_ENOENT) {
1569 errno = saveerrno;
1570 rc = 0;
1571 fsm->exists = 0;
1572 } else if (rc == 0) {
1573 fsm->exists = 1;
1574 }
1575 } else {
1576 /* Skip %ghost files on build. */
1577 fsm->exists = 0;
1578 }
1579 return rc;
1580 }
1581 #endif
1582
1583 #define IS_DEV_LOG(_x) \
1584 ((_x) != NULL && strlen(_x) >= (sizeof("/dev/log")-1) && \
1585 !strncmp((_x), "/dev/log", sizeof("/dev/log")-1) && \
1586 ((_x)[sizeof("/dev/log")-1] == '\0' || \
1587 (_x)[sizeof("/dev/log")-1] == ';'))
1588
1589 /*@-compmempass@*/
1590 int fsmStage(IOSM_t fsm, iosmFileStage stage)
1591 {
1592 #ifdef NOTUSED
1593 iosmFileStage prevStage = fsm->stage;
1594 const char * const prev = iosmFileStageString(prevStage);
1595 #endif
1596 const char * const cur = iosmFileStageString(stage);
1597 struct stat * st = &fsm->sb;
1598 struct stat * ost = &fsm->osb;
1599 int saveerrno = errno;
1600 int rc = fsm->rc;
1601 int i;
1602
1603 #define _fafilter(_a) \
1604 (!((_a) == FA_CREATE || (_a) == FA_ERASE || (_a) == FA_COPYIN || (_a) == FA_COPYOUT) \
1605 ? iosmFileActionString(_a) : "")
1606
1607 if (stage & IOSM_DEAD) {
1608 /* do nothing */
1609 } else if (stage & IOSM_INTERNAL) {
1610 if (fsm->debug && !(stage & IOSM_SYSCALL))
1611 rpmlog(RPMLOG_DEBUG, " %8s %06o%3d (%4d,%4d)%12lu %s %s\n",
1612 cur,
1613 (unsigned)st->st_mode, (int)st->st_nlink,
1614 (int)st->st_uid, (int)st->st_gid, (unsigned long)st->st_size,
1615 (fsm->path ? fsm->path : ""),
1616 _fafilter(fsm->action));
1617 } else {
1618 const char * apath = NULL;
1619 if (fsm->path)
1620 (void) urlPath(fsm->path, &apath);
1621 fsm->stage = stage;
1622 if (fsm->debug || !(stage & IOSM_VERBOSE))
1623 rpmlog(RPMLOG_DEBUG, "%-8s %06o%3d (%4d,%4d)%12lu %s %s\n",
1624 cur,
1625 (unsigned)st->st_mode, (int)st->st_nlink,
1626 (int)st->st_uid, (int)st->st_gid, (unsigned long)st->st_size,
1627 (apath ? apath + fsm->astriplen : ""),
1628 _fafilter(fsm->action));
1629 }
1630 #undef _fafilter
1631
1632 switch (stage) {
1633 case IOSM_UNKNOWN:
1634 break;
1635 case IOSM_PKGINSTALL:
1636 while (1) {
1637 /* Clean fsm, free'ing memory. Read next archive header. */
1638 rc = fsmUNSAFE(fsm, IOSM_INIT);
1639
1640 /* Exit on end-of-payload. */
1641 if (rc == IOSMERR_HDR_TRAILER) {
1642 rc = 0;
1643 /*@loopbreak@*/ break;
1644 }
1645
1646 /* Exit on error. */
1647 if (rc) {
1648 fsm->postpone = 1;
1649 (void) fsmNext(fsm, IOSM_UNDO);
1650 /*@loopbreak@*/ break;
1651 }
1652
1653 /* Extract file from archive. */
1654 rc = fsmNext(fsm, IOSM_PROCESS);
1655 if (rc) {
1656 (void) fsmNext(fsm, IOSM_UNDO);
1657 /*@loopbreak@*/ break;
1658 }
1659
1660 /* Notify on success. */
1661 (void) fsmNext(fsm, IOSM_NOTIFY);
1662
1663 rc = fsmNext(fsm, IOSM_FINI);
1664 if (rc) {
1665 /*@loopbreak@*/ break;
1666 }
1667 }
1668 break;
1669 case IOSM_PKGERASE:
1670 case IOSM_PKGCOMMIT:
1671 while (1) {
1672 /* Clean fsm, free'ing memory. */
1673 rc = fsmUNSAFE(fsm, IOSM_INIT);
1674
1675 /* Exit on end-of-payload. */
1676 if (rc == IOSMERR_HDR_TRAILER) {
1677 rc = 0;
1678 /*@loopbreak@*/ break;
1679 }
1680
1681 /* Rename/erase next item. */
1682 if (fsmNext(fsm, IOSM_FINI))
1683 /*@loopbreak@*/ break;
1684 }
1685 break;
1686 case IOSM_PKGBUILD:
1687 while (1) {
1688
1689 rc = fsmUNSAFE(fsm, IOSM_INIT);
1690
1691 /* Exit on end-of-payload. */
1692 if (rc == IOSMERR_HDR_TRAILER) {
1693 rc = 0;
1694 /*@loopbreak@*/ break;
1695 }
1696
1697 /* Exit on error. */
1698 if (rc) {
1699 fsm->postpone = 1;
1700 (void) fsmNext(fsm, IOSM_UNDO);
1701 /*@loopbreak@*/ break;
1702 }
1703
1704 /* Copy file into archive. */
1705 rc = fsmNext(fsm, IOSM_PROCESS);
1706 if (rc) {
1707 (void) fsmNext(fsm, IOSM_UNDO);
1708 /*@loopbreak@*/ break;
1709 }
1710
1711 /* Notify on success. */
1712 (void) fsmNext(fsm, IOSM_NOTIFY);
1713
1714 if (fsmNext(fsm, IOSM_FINI))
1715 /*@loopbreak@*/ break;
1716 }
1717
1718 /* Flush partial sets of hard linked files. */
1719 if (!(fsm->mapFlags & IOSM_ALL_HARDLINKS)) {
1720 int nlink, j;
1721 while ((fsm->li = fsm->links) != NULL) {
1722 fsm->links = fsm->li->next;
1723 fsm->li->next = NULL;
1724
1725 /* Re-calculate link count for archive header. */
1726 for (j = -1, nlink = 0, i = 0; i < fsm->li->nlink; i++) {
1727 if (fsm->li->filex[i] < 0)
1728 /*@innercontinue@*/ continue;
1729 nlink++;
1730 if (j == -1) j = i;
1731 }
1732 /* XXX force the contents out as well. */
1733 if (j != 0) {
1734 fsm->li->filex[0] = fsm->li->filex[j];
1735 fsm->li->filex[j] = -1;
1736 }
1737 fsm->li->sb.st_nlink = nlink;
1738
1739 fsm->sb = fsm->li->sb; /* structure assignment */
1740 fsm->osb = fsm->sb; /* structure assignment */
1741
1742 if (!rc) rc = writeLinkedFile(fsm);
1743
1744 fsm->li = freeHardLink(fsm->li);
1745 }
1746 }
1747
1748 if (!rc)
1749 rc = fsmNext(fsm, IOSM_TRAILER);
1750
1751 break;
1752 case IOSM_CREATE:
1753 fsm->path = _free(fsm->path);
1754 fsm->lpath = _free(fsm->lpath);
1755 fsm->opath = _free(fsm->opath);
1756 fsm->dnlx = _free(fsm->dnlx);
1757
1758 fsm->ldn = _free(fsm->ldn);
1759 fsm->ldnalloc = fsm->ldnlen = 0;
1760
1761 fsm->rdsize = fsm->wrsize = 0;
1762 fsm->rdbuf = fsm->rdb = _free(fsm->rdb);
1763 fsm->wrbuf = fsm->wrb = _free(fsm->wrb);
1764 if (fsm->goal == IOSM_PKGINSTALL || fsm->goal == IOSM_PKGBUILD) {
1765 fsm->rdsize = 16 * BUFSIZ;
1766 fsm->rdbuf = fsm->rdb = xmalloc(fsm->rdsize);
1767 fsm->wrsize = 16 * BUFSIZ;
1768 fsm->wrbuf = fsm->wrb = xmalloc(fsm->wrsize);
1769 }
1770
1771 fsm->mkdirsdone = 0;
1772 fsm->ix = -1;
1773 fsm->links = NULL;
1774 fsm->li = NULL;
1775 errno = 0; /* XXX get rid of EBADF */
1776
1777 /* Detect and create directories not explicitly in package. */
1778 if (fsm->goal == IOSM_PKGINSTALL) {
1779 /*@-compdef@*/
1780 rc = fsmNext(fsm, IOSM_MKDIRS);
1781 /*@=compdef@*/
1782 if (!rc) fsm->mkdirsdone = 1;
1783 }
1784
1785 break;
1786 case IOSM_INIT:
1787 fsm->path = _free(fsm->path);
1788 fsm->lpath = _free(fsm->lpath);
1789 fsm->postpone = 0;
1790 fsm->diskchecked = fsm->exists = 0;
1791 fsm->subdir = NULL;
1792 fsm->suffix = (fsm->sufbuf[0] != '\0' ? fsm->sufbuf : NULL);
1793 fsm->action = FA_UNKNOWN;
1794 fsm->osuffix = NULL;
1795 fsm->nsuffix = NULL;
1796
1797 if (fsm->goal == IOSM_PKGINSTALL) {
1798 /* Read next header from payload, checking for end-of-payload. */
1799 rc = fsmUNSAFE(fsm, IOSM_NEXT);
1800 }
1801 if (rc) break;
1802
1803 /* Identify mapping index. */
1804 fsm->ix = ((fsm->goal == IOSM_PKGINSTALL)
1805 ? mapFind(fsm->iter, fsm->path) : mapNextIterator(fsm->iter));
1806
1807 if (!(fsmGetFi(fsm)->mapflags & IOSM_PAYLOAD_LIST)) {
1808 /* Detect end-of-loop and/or mapping error. */
1809 if (!(fsmGetFi(fsm)->mapflags & IOSM_PAYLOAD_EXTRACT)) {
1810 if (fsm->ix < 0) {
1811 if (fsm->goal == IOSM_PKGINSTALL) {
1812 #if 0
1813 rpmlog(RPMLOG_WARNING,
1814 _("archive file %s was not found in header file list\n"),
1815 fsm->path);
1816 #endif
1817 if (fsm->failedFile && *fsm->failedFile == NULL)
1818 *fsm->failedFile = xstrdup(fsm->path);
1819 rc = IOSMERR_UNMAPPED_FILE;
1820 } else {
1821 rc = IOSMERR_HDR_TRAILER;
1822 }
1823 break;
1824 }
1825 }
1826
1827 /* On non-install, mode must be known so that dirs don't get suffix. */
1828 if (fsm->goal != IOSM_PKGINSTALL) {
1829 rpmfi fi = fsmGetFi(fsm);
1830 st->st_mode = fi->fmodes[fsm->ix];
1831 }
1832 }
1833
1834 /* Generate file path. */
1835 rc = fsmNext(fsm, IOSM_MAP);
1836 if (rc) break;
1837
1838 /* Perform lstat/stat for disk file. */
1839 #ifdef NOTYET
1840 rc = fsmStat(fsm);
1841 #else
1842 if (fsm->path != NULL &&
1843 !(fsm->goal == IOSM_PKGINSTALL && S_ISREG(st->st_mode)))
1844 {
1845 rc = fsmUNSAFE(fsm, (!(fsm->mapFlags & IOSM_FOLLOW_SYMLINKS)
1846 ? IOSM_LSTAT : IOSM_STAT));
1847 if (rc == IOSMERR_ENOENT) {
1848 errno = saveerrno;
1849 rc = 0;
1850 fsm->exists = 0;
1851 } else if (rc == 0) {
1852 fsm->exists = 1;
1853 }
1854 } else {
1855 /* Skip %ghost files on build. */
1856 fsm->exists = 0;
1857 }
1858 #endif
1859 fsm->diskchecked = 1;
1860 if (rc) break;
1861
1862 /* On non-install, the disk file stat is what's remapped. */
1863 if (fsm->goal != IOSM_PKGINSTALL)
1864 *st = *ost; /* structure assignment */
1865
1866 /* Remap file perms, owner, and group. */
1867 rc = fsmMapAttrs(fsm);
1868 if (rc) break;
1869
1870 fsm->postpone = iosmFileActionSkipped(fsm->action);
1871 if (fsm->goal == IOSM_PKGINSTALL || fsm->goal == IOSM_PKGBUILD) {
1872 /*@-evalorder@*/ /* FIX: saveHardLink can modify fsm */
1873 if (S_ISREG(st->st_mode) && st->st_nlink > 1)
1874 fsm->postpone = saveHardLink(fsm);
1875 /*@=evalorder@*/
1876 }
1877 if (fsmGetFi(fsm)->mapflags & IOSM_PAYLOAD_LIST) fsm->postpone = 1;
1878 break;
1879 case IOSM_PRE:
1880 break;
1881 case IOSM_MAP:
1882 rc = fsmMapPath(fsm);
1883 break;
1884 case IOSM_MKDIRS:
1885 rc = fsmMkdirs(fsm);
1886 break;
1887 case IOSM_RMDIRS:
1888 if (fsm->dnlx)
1889 rc = fsmRmdirs(fsm);
1890 break;
1891 case IOSM_PROCESS:
1892 if (fsm->postpone) {
1893 if (fsm->goal == IOSM_PKGINSTALL) {
1894 /* XXX Skip over file body, archive headers already done. */
1895 if (S_ISREG(st->st_mode))
1896 rc = fsmNext(fsm, IOSM_EAT);
1897 }
1898 break;
1899 }
1900
1901 if (fsm->goal == IOSM_PKGBUILD) {
1902 if (fsm->fflags & RPMFILE_GHOST) /* XXX Don't if %ghost file. */
1903 break;
1904 if (S_ISREG(st->st_mode) && st->st_nlink > 1) {
1905 struct hardLink_s * li, * prev;
1906
1907 if (!(fsm->mapFlags & IOSM_ALL_HARDLINKS)) break;
1908 rc = writeLinkedFile(fsm);
1909 if (rc) break; /* W2DO? */
1910
1911 for (li = fsm->links, prev = NULL; li; prev = li, li = li->next)
1912 if (li == fsm->li)
1913 /*@loopbreak@*/ break;
1914
1915 if (prev == NULL)
1916 fsm->links = fsm->li->next;
1917 else
1918 prev->next = fsm->li->next;
1919 fsm->li->next = NULL;
1920 fsm->li = freeHardLink(fsm->li);
1921 } else {
1922 rc = writeFile(fsm, 1);
1923 }
1924 break;
1925 }
1926
1927 if (fsm->goal != IOSM_PKGINSTALL)
1928 break;
1929
1930 if (S_ISREG(st->st_mode) && fsm->lpath != NULL) {
1931 const char * opath = fsm->opath;
1932 char * t = xmalloc(strlen(fsm->lpath+1) + strlen(fsm->suffix) + 1);
1933 (void) stpcpy(t, fsm->lpath+1);
1934 fsm->opath = t;
1935 /* XXX link(fsm->opath, fsm->path) */
1936 rc = fsmNext(fsm, IOSM_LINK);
1937 if (fsm->failedFile && rc != 0 && *fsm->failedFile == NULL) {
1938 *fsm->failedFile = xstrdup(fsm->path);
1939 }
1940 fsm->opath = _free(fsm->opath);
1941 fsm->opath = opath;
1942 break; /* XXX so that delayed hard links get skipped. */
1943 }
1944 if (S_ISREG(st->st_mode)) {
1945 const char * path = fsm->path;
1946 if (fsm->osuffix)
1947 fsm->path = fsmFsPath(fsm, st, NULL, NULL);
1948 rc = fsmUNSAFE(fsm, IOSM_VERIFY);
1949
1950 if (rc == 0 && fsm->osuffix) {
1951 const char * opath = fsm->opath;
1952 fsm->opath = fsm->path;
1953 fsm->path = fsmFsPath(fsm, st, NULL, fsm->osuffix);
1954 rc = fsmNext(fsm, IOSM_RENAME);
1955 if (!rc)
1956 rpmlog(RPMLOG_WARNING,
1957 _("%s saved as %s\n"),
1958 (fsm->opath ? fsm->opath : ""),
1959 (fsm->path ? fsm->path : ""));
1960 fsm->path = _free(fsm->path);
1961 fsm->opath = opath;
1962 }
1963
1964 /*@-dependenttrans@*/
1965 fsm->path = path;
1966 /*@=dependenttrans@*/
1967 if (!(rc == IOSMERR_ENOENT)) return rc;
1968 rc = extractRegular(fsm);
1969 } else if (S_ISDIR(st->st_mode)) {
1970 mode_t st_mode = st->st_mode;
1971 rc = fsmUNSAFE(fsm, IOSM_VERIFY);
1972 if (rc == IOSMERR_ENOENT) {
1973 st->st_mode &= ~07777; /* XXX abuse st->st_mode */
1974 st->st_mode |= 00700;
1975 rc = fsmNext(fsm, IOSM_MKDIR);
1976 st->st_mode = st_mode; /* XXX restore st->st_mode */
1977 }
1978 } else if (S_ISLNK(st->st_mode)) {
1979 assert(fsm->lpath != NULL);
1980 /*@=dependenttrans@*/
1981 rc = fsmUNSAFE(fsm, IOSM_VERIFY);
1982 if (rc == IOSMERR_ENOENT)
1983 rc = fsmNext(fsm, IOSM_SYMLINK);
1984 } else if (S_ISFIFO(st->st_mode)) {
1985 mode_t st_mode = st->st_mode;
1986 /* This mimics cpio S_ISSOCK() behavior but probably isnt' right */
1987 rc = fsmUNSAFE(fsm, IOSM_VERIFY);
1988 if (rc == IOSMERR_ENOENT) {
1989 st->st_mode = 0000; /* XXX abuse st->st_mode */
1990 rc = fsmNext(fsm, IOSM_MKFIFO);
1991 st->st_mode = st_mode; /* XXX restore st->st_mode */
1992 }
1993 } else if (S_ISCHR(st->st_mode) ||
1994 S_ISBLK(st->st_mode) ||
1995 /*@-unrecog@*/ S_ISSOCK(st->st_mode) /*@=unrecog@*/)
1996 {
1997 rc = fsmUNSAFE(fsm, IOSM_VERIFY);
1998 if (rc == IOSMERR_ENOENT)
1999 rc = fsmNext(fsm, IOSM_MKNOD);
2000 } else {
2001 /* XXX Repackaged payloads may be missing files. */
2002 if (fsm->repackaged)
2003 break;
2004
2005 /* XXX Special case /dev/log, which shouldn't be packaged anyways */
2006 if (!IS_DEV_LOG(fsm->path))
2007 rc = IOSMERR_UNKNOWN_FILETYPE;
2008 }
2009 if (S_ISREG(st->st_mode) && st->st_nlink > 1) {
2010 fsm->li->createdPath = fsm->li->linkIndex;
2011 rc = fsmMakeLinks(fsm);
2012 }
2013 break;
2014 case IOSM_POST:
2015 break;
2016 case IOSM_MKLINKS:
2017 rc = fsmMakeLinks(fsm);
2018 break;
2019 case IOSM_NOTIFY: /* XXX move from fsm to psm -> tsm */
2020 if (fsm->goal == IOSM_PKGINSTALL || fsm->goal == IOSM_PKGBUILD) {
2021 rpmts ts = fsmGetTs(fsm);
2022 rpmfi fi = fsmGetFi(fsm);
2023 void * ptr;
2024 rpmuint64_t archivePos = fdGetCpioPos(fsm->cfd);
2025 if (archivePos > fi->archivePos) {
2026 fi->archivePos = (unsigned long long) archivePos;
2027 ptr = rpmtsNotify(ts, fi->te, RPMCALLBACK_INST_PROGRESS,
2028 fi->archivePos, fi->archiveSize);
2029 }
2030 }
2031 break;
2032 case IOSM_UNDO:
2033 if (fsm->postpone)
2034 break;
2035 if (fsm->goal == IOSM_PKGINSTALL) {
2036 /* XXX only erase if temp fn w suffix is in use */
2037 if (fsm->sufbuf[0] != '\0')
2038 (void) fsmNext(fsm,
2039 (S_ISDIR(st->st_mode) ? IOSM_RMDIR : IOSM_UNLINK));
2040
2041 #ifdef NOTYET /* XXX remove only dirs just created, not all. */
2042 if (fsm->dnlx)
2043 (void) fsmNext(fsm, IOSM_RMDIRS);
2044 #endif
2045 errno = saveerrno;
2046 }
2047 if (fsm->failedFile && *fsm->failedFile == NULL)
2048 *fsm->failedFile = xstrdup(fsm->path);
2049 break;
2050 case IOSM_FINI:
2051 if (!fsm->postpone && fsm->commit) {
2052 if (fsm->goal == IOSM_PKGINSTALL)
2053 rc = ((S_ISREG(st->st_mode) && st->st_nlink > 1)
2054 ? fsmCommitLinks(fsm) : fsmNext(fsm, IOSM_COMMIT));
2055 if (fsm->goal == IOSM_PKGCOMMIT)
2056 rc = fsmNext(fsm, IOSM_COMMIT);
2057 if (fsm->goal == IOSM_PKGERASE)
2058 rc = fsmNext(fsm, IOSM_COMMIT);
2059 }
2060 fsm->path = _free(fsm->path);
2061 fsm->lpath = _free(fsm->lpath);
2062 fsm->opath = _free(fsm->opath);
2063 memset(st, 0, sizeof(*st));
2064 memset(ost, 0, sizeof(*ost));
2065 break;
2066 case IOSM_COMMIT:
2067 /* Rename pre-existing modified or unmanaged file. */
2068 if (fsm->osuffix && fsm->diskchecked &&
2069 (fsm->exists || (fsm->goal == IOSM_PKGINSTALL && S_ISREG(st->st_mode))))
2070 {
2071 const char * opath = fsm->opath;
2072 const char * path = fsm->path;
2073 fsm->opath = fsmFsPath(fsm, st, NULL, NULL);
2074 fsm->path = fsmFsPath(fsm, st, NULL, fsm->osuffix);
2075 rc = fsmNext(fsm, IOSM_RENAME);
2076 if (!rc) {
2077 rpmlog(RPMLOG_WARNING, _("%s saved as %s\n"),
2078 (fsm->opath ? fsm->opath : ""),
2079 (fsm->path ? fsm->path : ""));
2080 }
2081 fsm->path = _free(fsm->path);
2082 fsm->path = path;
2083 fsm->opath = _free(fsm->opath);
2084 fsm->opath = opath;
2085 }
2086
2087 /* Remove erased files. */
2088 if (fsm->goal == IOSM_PKGERASE) {
2089 if (fsm->action == FA_ERASE) {
2090 rpmfi fi = fsmGetFi(fsm);
2091 if (S_ISDIR(st->st_mode)) {
2092 rc = fsmNext(fsm, IOSM_RMDIR);
2093 if (!rc) break;
2094 switch (rc) {
2095 case IOSMERR_ENOENT: /* XXX rmdir("/") linux 2.2.x kernel hack */
2096 case IOSMERR_ENOTEMPTY:
2097 /* XXX make sure that build side permits %missingok on directories. */
2098 if (fsm->fflags & RPMFILE_MISSINGOK)
2099 /*@innerbreak@*/ break;
2100
2101 /* XXX common error message. */
2102 rpmlog(
2103 (fsm->strict_erasures ? RPMLOG_ERR : RPMLOG_DEBUG),
2104 _("%s rmdir of %s failed: Directory not empty\n"),
2105 rpmfiTypeString(fi), fsm->path);
2106 /*@innerbreak@*/ break;
2107 default:
2108 rpmlog(
2109 (fsm->strict_erasures ? RPMLOG_ERR : RPMLOG_DEBUG),
2110 _("%s rmdir of %s failed: %s\n"),
2111 rpmfiTypeString(fi), fsm->path, strerror(errno));
2112 /*@innerbreak@*/ break;
2113 }
2114 } else {
2115 rc = fsmNext(fsm, IOSM_UNLINK);
2116 if (!rc) break;
2117 switch (rc) {
2118 case IOSMERR_ENOENT:
2119 if (fsm->fflags & RPMFILE_MISSINGOK)
2120 /*@innerbreak@*/ break;
2121 /*@fallthrough@*/
2122 default:
2123 rpmlog(
2124 (fsm->strict_erasures ? RPMLOG_ERR : RPMLOG_DEBUG),
2125 _(" %s: unlink of %s failed: %s\n"),
2126 rpmfiTypeString(fi), fsm->path, strerror(errno));
2127 /*@innerbreak@*/ break;
2128 }
2129 }
2130 }
2131 /* XXX Failure to remove is not (yet) cause for failure. */
2132 if (!fsm->strict_erasures) rc = 0;
2133 break;
2134 }
2135
2136 /* XXX Special case /dev/log, which shouldn't be packaged anyways */
2137 if (!(fsmGetFi(fsm)->mapflags & IOSM_PAYLOAD_EXTRACT)) {
2138 if (!S_ISSOCK(st->st_mode) && !IS_DEV_LOG(fsm->path)) {
2139 /* Rename temporary to final file name. */
2140 if (!S_ISDIR(st->st_mode) &&
2141 (fsm->subdir || fsm->suffix || fsm->nsuffix))
2142 {
2143 fsm->opath = fsm->path;
2144 fsm->path = fsmFsPath(fsm, st, NULL, fsm->nsuffix);
2145 rc = fsmNext(fsm, IOSM_RENAME);
2146 if (rc)
2147 (void) Unlink(fsm->opath);
2148 else if (fsm->nsuffix) {
2149 const char * opath = fsmFsPath(fsm, st, NULL, NULL);
2150 rpmlog(RPMLOG_WARNING, _("%s created as %s\n"),
2151 (opath ? opath : ""),
2152 (fsm->path ? fsm->path : ""));
2153 opath = _free(opath);
2154 }
2155 fsm->opath = _free(fsm->opath);
2156 }
2157 /*
2158 * Set file security context (if not disabled).
2159 */
2160 if (!rc && !getuid()) {
2161 rc = fsmMapFContext(fsm);
2162 if (!rc)
2163 rc = fsmNext(fsm, IOSM_LSETFCON);
2164 fsm->fcontext = NULL;
2165 }
2166 if (S_ISLNK(st->st_mode)) {
2167 if (!rc && !getuid())
2168 rc = fsmNext(fsm, IOSM_LCHOWN);
2169 } else {
2170 if (!rc && !getuid())
2171 rc = fsmNext(fsm, IOSM_CHOWN);
2172 if (!rc)
2173 rc = fsmNext(fsm, IOSM_CHMOD);
2174 if (!rc) {
2175 time_t mtime = st->st_mtime;
2176 rpmfi fi = fsmGetFi(fsm);
2177 if (fi->fmtimes)
2178 st->st_mtime = fi->fmtimes[fsm->ix];
2179 rc = fsmNext(fsm, IOSM_UTIME);
2180 st->st_mtime = mtime;
2181 }
2182 }
2183 }
2184 }
2185
2186 /* Notify on success. */
2187 if (!rc) rc = fsmNext(fsm, IOSM_NOTIFY);
2188 else if (fsm->failedFile && *fsm->failedFile == NULL) {
2189 *fsm->failedFile = fsm->path;
2190 fsm->path = NULL;
2191 }
2192 break;
2193 case IOSM_DESTROY:
2194 fsm->path = _free(fsm->path);
2195
2196 /* Check for hard links missing from payload. */
2197 while ((fsm->li = fsm->links) != NULL) {
2198 fsm->links = fsm->li->next;
2199 fsm->li->next = NULL;
2200 if (fsm->goal == IOSM_PKGINSTALL &&
2201 fsm->commit && fsm->li->linksLeft)
2202 {
2203 for (i = 0 ; i < fsm->li->linksLeft; i++) {
2204 if (fsm->li->filex[i] < 0)
2205 /*@innercontinue@*/ continue;
2206 rc = IOSMERR_MISSING_HARDLINK;
2207 if (fsm->failedFile && *fsm->failedFile == NULL) {
2208 fsm->ix = fsm->li->filex[i];
2209 if (!fsmNext(fsm, IOSM_MAP)) {
2210 *fsm->failedFile = fsm->path;
2211 fsm->path = NULL;
2212 }
2213 }
2214 /*@loopbreak@*/ break;
2215 }
2216 }
2217 if (fsm->goal == IOSM_PKGBUILD &&
2218 (fsm->mapFlags & IOSM_ALL_HARDLINKS))
2219 {
2220 rc = IOSMERR_MISSING_HARDLINK;
2221 }
2222 fsm->li = freeHardLink(fsm->li);
2223 }
2224 fsm->ldn = _free(fsm->ldn);
2225 fsm->ldnalloc = fsm->ldnlen = 0;
2226 fsm->rdbuf = fsm->rdb = _free(fsm->rdb);
2227 fsm->wrbuf = fsm->wrb = _free(fsm->wrb);
2228 break;
2229 case IOSM_VERIFY:
2230 if (fsm->diskchecked && !fsm->exists) {
2231 rc = IOSMERR_ENOENT;
2232 break;
2233 }
2234 if (S_ISREG(st->st_mode)) {
2235 char * path = alloca(strlen(fsm->path) + sizeof("-RPMDELETE"));
2236 (void) stpcpy( stpcpy(path, fsm->path), "-RPMDELETE");
2237 /*
2238 * XXX HP-UX (and other os'es) don't permit unlink on busy
2239 * XXX files.
2240 */
2241 fsm->opath = fsm->path;
2242 fsm->path = path;
2243 rc = fsmNext(fsm, IOSM_RENAME);
2244 if (!rc)
2245 (void) fsmNext(fsm, IOSM_UNLINK);
2246 else
2247 rc = IOSMERR_UNLINK_FAILED;
2248 fsm->path = fsm->opath;
2249 fsm->opath = NULL;
2250 return (rc ? rc : IOSMERR_ENOENT); /* XXX HACK */
2251 /*@notreached@*/ break;
2252 } else if (S_ISDIR(st->st_mode)) {
2253 if (S_ISDIR(ost->st_mode)) return 0;
2254 if (S_ISLNK(ost->st_mode)) {
2255 rc = fsmUNSAFE(fsm, IOSM_STAT);
2256 if (rc == IOSMERR_ENOENT) rc = 0;
2257 if (rc) break;
2258 errno = saveerrno;
2259 if (S_ISDIR(ost->st_mode)) return 0;
2260 }
2261 } else if (S_ISLNK(st->st_mode)) {
2262 if (S_ISLNK(ost->st_mode)) {
2263 /* XXX NUL terminated result in fsm->rdbuf, len in fsm->rdnb. */
2264 rc = fsmUNSAFE(fsm, IOSM_READLINK);
2265 errno = saveerrno;
2266 if (rc) break;
2267 if (!strcmp(fsm->lpath, fsm->rdbuf)) return 0;
2268 }
2269 } else if (S_ISFIFO(st->st_mode)) {
2270 if (S_ISFIFO(ost->st_mode)) return 0;
2271 } else if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
2272 if ((S_ISCHR(ost->st_mode) || S_ISBLK(ost->st_mode)) &&
2273 (ost->st_rdev == st->st_rdev)) return 0;
2274 } else if (S_ISSOCK(st->st_mode)) {
2275 if (S_ISSOCK(ost->st_mode)) return 0;
2276 }
2277 /* XXX shouldn't do this with commit/undo. */
2278 rc = 0;
2279 if (fsm->stage == IOSM_PROCESS) rc = fsmNext(fsm, IOSM_UNLINK);
2280 if (rc == 0) rc = IOSMERR_ENOENT;
2281 return (rc ? rc : IOSMERR_ENOENT); /* XXX HACK */
2282 /*@notreached@*/ break;
2283
2284 case IOSM_UNLINK:
2285 case IOSM_RENAME:
2286 case IOSM_MKDIR:
2287 case IOSM_RMDIR:
2288 case IOSM_LSETFCON:
2289 case IOSM_CHOWN:
2290 case IOSM_LCHOWN:
2291 case IOSM_CHMOD:
2292 case IOSM_UTIME:
2293 case IOSM_SYMLINK:
2294 case IOSM_LINK:
2295 case IOSM_MKFIFO:
2296 case IOSM_MKNOD:
2297 case IOSM_LSTAT:
2298 case IOSM_STAT:
2299 case IOSM_READLINK:
2300 case IOSM_CHROOT:
2301 rc = iosmStage(fsm, stage);
2302 break;
2303
2304 case IOSM_NEXT:
2305 case IOSM_EAT:
2306 case IOSM_POS:
2307 case IOSM_PAD:
2308 case IOSM_TRAILER:
2309 case IOSM_HREAD:
2310 case IOSM_HWRITE:
2311 case IOSM_DREAD:
2312 case IOSM_DWRITE:
2313 rc = iosmStage(fsm, stage);
2314 break;
2315
2316 case IOSM_ROPEN:
2317 case IOSM_READ:
2318 case IOSM_RCLOSE:
2319 rc = iosmStage(fsm, stage);
2320 break;
2321 case IOSM_WOPEN:
2322 case IOSM_WRITE:
2323 case IOSM_WCLOSE:
2324 rc = iosmStage(fsm, stage);
2325 break;
2326
2327 default:
2328 break;
2329 }
2330
2331 if (!(stage & IOSM_INTERNAL)) {
2332 fsm->rc = (rc == IOSMERR_HDR_TRAILER ? 0 : rc);
2333 }
2334 return rc;
2335 }
2336 /*@=compmempass@*/