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