rpm 5.2.1
|
00001 00006 #include "system.h" 00007 00008 #include <rpmio_internal.h> /* XXX urlPath, fdGetCpioPos */ 00009 #include <rpmcb.h> /* XXX fnpyKey */ 00010 #include <rpmtag.h> 00011 #include <rpmtypes.h> 00012 00013 #define _RPMFI_INTERNAL 00014 #include "rpmfi.h" 00015 00016 #define _IOSM_INTERNAL 00017 #include <fsm.h> 00018 #define fsmUNSAFE fsmStage 00019 00020 #if defined(SUPPORT_AR_PAYLOADS) 00021 #include "ar.h" 00022 #endif 00023 #include "cpio.h" 00024 #include "tar.h" 00025 00026 #define _USE_RPMTE 00027 #if defined(_USE_RPMTE) 00028 #include "rpmte.h" 00029 #endif 00030 #include "rpmts.h" 00031 #include "rpmsq.h" 00032 00033 #include "ugid.h" /* XXX unameToUid() and gnameToGid() */ 00034 00035 #include "debug.h" 00036 00037 /*@access FD_t @*/ /* XXX void ptr args */ 00038 /*@access FSMI_t @*/ 00039 /*@access IOSM_t @*/ 00040 /*@access IOSMI_t @*/ 00041 00042 /*@access rpmfi @*/ 00043 00044 /*@access rpmsx @*/ /* XXX cast */ 00045 /*@access rpmte @*/ /* XXX cast */ 00046 /*@access rpmts @*/ /* XXX cast */ 00047 00048 #define alloca_strdup(_s) strcpy(alloca(strlen(_s)+1), (_s)) 00049 00050 #define _FSM_DEBUG 0 00051 /*@unchecked@*/ 00052 int _fsm_debug = _FSM_DEBUG; 00053 00054 /*@-exportheadervar@*/ 00055 /*@unchecked@*/ 00056 int _fsm_threads = 0; 00057 /*@=exportheadervar@*/ 00058 00064 static rpmts fsmGetTs(const IOSM_t fsm) 00065 /*@*/ 00066 { 00067 const FSMI_t iter = fsm->iter; 00068 /*@-compdef -refcounttrans -retexpose -usereleased @*/ 00069 return (iter ? iter->ts : NULL); 00070 /*@=compdef =refcounttrans =retexpose =usereleased @*/ 00071 } 00072 00078 static rpmfi fsmGetFi(const IOSM_t fsm) 00079 /*@*/ 00080 { 00081 const FSMI_t iter = fsm->iter; 00082 /*@-compdef -refcounttrans -retexpose -usereleased @*/ 00083 return (iter ? iter->fi : NULL); 00084 /*@=compdef =refcounttrans =retexpose =usereleased @*/ 00085 } 00086 00087 #define SUFFIX_RPMORIG ".rpmorig" 00088 #define SUFFIX_RPMSAVE ".rpmsave" 00089 #define SUFFIX_RPMNEW ".rpmnew" 00090 00099 static /*@only@*//*@null@*/ 00100 const char * fsmFsPath(/*@special@*/ /*@null@*/ const IOSM_t fsm, 00101 /*@null@*/ const struct stat * st, 00102 /*@null@*/ const char * subdir, 00103 /*@null@*/ const char * suffix) 00104 /*@uses fsm->dirName, fsm->baseName */ 00105 /*@*/ 00106 { 00107 const char * s = NULL; 00108 00109 if (fsm) { 00110 char * t; 00111 int nb; 00112 nb = strlen(fsm->dirName) + 00113 (st && !S_ISDIR(st->st_mode) ? (subdir ? strlen(subdir) : 0) : 0) + 00114 (st && !S_ISDIR(st->st_mode) ? (suffix ? strlen(suffix) : 0) : 0) + 00115 strlen(fsm->baseName) + 1; 00116 s = t = xmalloc(nb); 00117 t = stpcpy(t, fsm->dirName); 00118 if (st && !S_ISDIR(st->st_mode)) 00119 if (subdir) t = stpcpy(t, subdir); 00120 t = stpcpy(t, fsm->baseName); 00121 if (st && !S_ISDIR(st->st_mode)) 00122 if (suffix) t = stpcpy(t, suffix); 00123 } 00124 return s; 00125 } 00126 00132 static /*@null@*/ void * mapFreeIterator(/*@only@*//*@null@*/ void * p) 00133 /*@globals fileSystem @*/ 00134 /*@modifies fileSystem @*/ 00135 { 00136 FSMI_t iter = p; 00137 if (iter) { 00138 iter->fi = rpmfiUnlink(iter->fi, "mapIterator"); 00139 /*@-internalglobs@*/ /* XXX rpmswExit() */ 00140 (void)rpmtsFree(iter->ts); 00141 iter->ts = NULL; 00142 /*@=internalglobs@*/ 00143 } 00144 return _free(p); 00145 } 00146 00153 static void * 00154 mapInitIterator(rpmfi fi, int reverse) 00155 /*@modifies fi @*/ 00156 { 00157 FSMI_t iter = NULL; 00158 00159 iter = xcalloc(1, sizeof(*iter)); 00160 /*@-assignexpose -castexpose @*/ 00161 iter->fi = rpmfiLink(fi, "mapIterator"); 00162 /*@=assignexpose =castexpose @*/ 00163 iter->reverse = reverse; 00164 iter->i = (iter->reverse ? (fi->fc - 1) : 0); 00165 iter->isave = iter->i; 00166 return iter; 00167 } 00168 00174 static int mapNextIterator(/*@null@*/ void * a) 00175 /*@*/ 00176 { 00177 FSMI_t iter = a; 00178 int i = -1; 00179 00180 if (iter) { 00181 /*@-onlytrans@*/ 00182 const rpmfi fi = iter->fi; 00183 /*@=onlytrans@*/ 00184 if (iter->reverse) { 00185 if (iter->i >= 0) i = iter->i--; 00186 } else { 00187 if (iter->i < (int)fi->fc) i = iter->i++; 00188 } 00189 iter->isave = i; 00190 } 00191 return i; 00192 } 00193 00196 static int cpioStrCmp(const void * a, const void * b) 00197 /*@*/ 00198 { 00199 const char * aurl = *(const char **)a; 00200 const char * burl = *(const char **)b; 00201 const char * afn = NULL; 00202 const char * bfn = NULL; 00203 00204 (void) urlPath(aurl, &afn); 00205 (void) urlPath(burl, &bfn); 00206 00207 #ifdef VERY_OLD_BUGGY_RPM_PACKAGES 00208 /* XXX Some rpm-2.4 packages from 1997 have basename only in payloads. */ 00209 if (strchr(afn, '/') == NULL) 00210 bfn = strrchr(bfn, '/') + 1; 00211 #endif 00212 00213 /* Match rpm-4.0 payloads with ./ prefixes. */ 00214 if (afn[0] == '.' && afn[1] == '/') afn += 2; 00215 if (bfn[0] == '.' && bfn[1] == '/') bfn += 2; 00216 00217 /* If either path is absolute, make it relative to '/'. */ 00218 if (afn[0] == '/') afn += 1; 00219 if (bfn[0] == '/') bfn += 1; 00220 00221 return strcmp(afn, bfn); 00222 } 00223 00230 static int mapFind(/*@null@*/ FSMI_t iter, const char * fsmPath) 00231 /*@modifies iter @*/ 00232 { 00233 int ix = -1; 00234 00235 if (iter) { 00236 /*@-onlytrans@*/ 00237 const rpmfi fi = iter->fi; 00238 /*@=onlytrans@*/ 00239 size_t fc = rpmfiFC(fi); 00240 if (fi && fc > 0 && fi->apath && fsmPath && *fsmPath) { 00241 const char ** p = NULL; 00242 00243 if (fi->apath != NULL) 00244 p = bsearch(&fsmPath, fi->apath, fc, sizeof(fsmPath), 00245 cpioStrCmp); 00246 if (p) { 00247 iter->i = p - fi->apath; 00248 ix = mapNextIterator(iter); 00249 } 00250 } 00251 } 00252 return ix; 00253 } 00254 00258 typedef struct dnli_s { 00259 rpmfi fi; 00260 /*@only@*/ /*@null@*/ 00261 char * active; 00262 int reverse; 00263 int isave; 00264 int i; 00265 } * DNLI_t; 00266 00272 static /*@null@*/ void * dnlFreeIterator(/*@only@*//*@null@*/ const void * a) 00273 /*@modifies a @*/ 00274 { 00275 if (a) { 00276 DNLI_t dnli = (void *)a; 00277 if (dnli->active) free(dnli->active); 00278 } 00279 return _free(a); 00280 } 00281 00284 static inline int dnlCount(/*@null@*/ const DNLI_t dnli) 00285 /*@*/ 00286 { 00287 return (int) (dnli ? dnli->fi->dc : 0); 00288 } 00289 00292 static inline int dnlIndex(/*@null@*/ const DNLI_t dnli) 00293 /*@*/ 00294 { 00295 return (dnli ? dnli->isave : -1); 00296 } 00297 00304 /*@-usereleased@*/ 00305 static /*@only@*/ /*@null@*/ 00306 void * dnlInitIterator(/*@special@*/ const IOSM_t fsm, 00307 int reverse) 00308 /*@uses fsm->iter @*/ 00309 /*@*/ 00310 { 00311 rpmfi fi = fsmGetFi(fsm); 00312 const char * dnl; 00313 DNLI_t dnli; 00314 int i, j; 00315 00316 if (fi == NULL) 00317 return NULL; 00318 dnli = xcalloc(1, sizeof(*dnli)); 00319 dnli->fi = fi; 00320 dnli->reverse = reverse; 00321 dnli->i = (int) (reverse ? fi->dc : 0); 00322 00323 if (fi->dc) { 00324 dnli->active = xcalloc(fi->dc, sizeof(*dnli->active)); 00325 00326 /* Identify parent directories not skipped. */ 00327 if ((fi = rpmfiInit(fi, 0)) != NULL) 00328 while ((i = rpmfiNext(fi)) >= 0) { 00329 if (!iosmFileActionSkipped(fi->actions[i])) dnli->active[fi->dil[i]] = 1; 00330 } 00331 00332 /* Exclude parent directories that are explicitly included. */ 00333 if ((fi = rpmfiInit(fi, 0)) != NULL) 00334 while ((i = rpmfiNext(fi)) >= 0) { 00335 rpmuint32_t dil; 00336 size_t dnlen, bnlen; 00337 00338 if (!S_ISDIR(fi->fmodes[i])) 00339 continue; 00340 00341 dil = fi->dil[i]; 00342 dnlen = strlen(fi->dnl[dil]); 00343 bnlen = strlen(fi->bnl[i]); 00344 00345 for (j = 0; j < (int)fi->dc; j++) { 00346 size_t jlen; 00347 00348 if (!dnli->active[j] || j == (int)dil) 00349 /*@innercontinue@*/ continue; 00350 (void) urlPath(fi->dnl[j], &dnl); 00351 jlen = strlen(dnl); 00352 if (jlen != (dnlen+bnlen+1)) 00353 /*@innercontinue@*/ continue; 00354 if (strncmp(dnl, fi->dnl[dil], dnlen)) 00355 /*@innercontinue@*/ continue; 00356 if (strncmp(dnl+dnlen, fi->bnl[i], bnlen)) 00357 /*@innercontinue@*/ continue; 00358 if (dnl[dnlen+bnlen] != '/' || dnl[dnlen+bnlen+1] != '\0') 00359 /*@innercontinue@*/ continue; 00360 /* This directory is included in the package. */ 00361 dnli->active[j] = 0; 00362 /*@innerbreak@*/ break; 00363 } 00364 } 00365 00366 /* Print only once per package. */ 00367 if (!reverse) { 00368 j = 0; 00369 for (i = 0; i < (int)fi->dc; i++) { 00370 if (!dnli->active[i]) continue; 00371 if (j == 0) { 00372 j = 1; 00373 rpmlog(RPMLOG_DEBUG, 00374 D_("========== Directories not explicitly included in package:\n")); 00375 } 00376 (void) urlPath(fi->dnl[i], &dnl); 00377 rpmlog(RPMLOG_DEBUG, "%10d %s\n", i, dnl); 00378 } 00379 if (j) 00380 rpmlog(RPMLOG_DEBUG, "==========\n"); 00381 } 00382 } 00383 return dnli; 00384 } 00385 /*@=usereleased@*/ 00386 00392 static /*@observer@*/ /*@null@*/ 00393 const char * dnlNextIterator(/*@null@*/ DNLI_t dnli) 00394 /*@modifies dnli @*/ 00395 { 00396 const char * dn = NULL; 00397 00398 if (dnli) { 00399 rpmfi fi = dnli->fi; 00400 int i = -1; 00401 00402 if (dnli->active) 00403 do { 00404 i = (!dnli->reverse ? dnli->i++ : --dnli->i); 00405 } while (i >= 0 && i < (int)fi->dc && !dnli->active[i]); 00406 00407 if (i >= 0 && i < (int)fi->dc) 00408 dn = fi->dnl[i]; 00409 else 00410 i = -1; 00411 dnli->isave = i; 00412 } 00413 return dn; 00414 } 00415 00416 #if defined(WITH_PTHREADS) 00417 static void * fsmThread(void * arg) 00418 /*@globals h_errno, fileSystem, internalState @*/ 00419 /*@modifies arg, fileSystem, internalState @*/ 00420 { 00421 IOSM_t fsm = arg; 00422 /*@-unqualifiedtrans@*/ 00423 return ((void *) ((long)fsmStage(fsm, fsm->nstage))); 00424 /*@=unqualifiedtrans@*/ 00425 } 00426 #endif 00427 00428 int fsmNext(IOSM_t fsm, iosmFileStage nstage) 00429 /*@globals h_errno, fileSystem, internalState @*/ 00430 /*@modifies fsm, fileSystem, internalState @*/ 00431 { 00432 fsm->nstage = nstage; 00433 #if defined(WITH_PTHREADS) 00434 if (fsm->multithreaded) 00435 return rpmsqJoin( rpmsqThread(fsmThread, fsm) ); 00436 #endif 00437 return fsmStage(fsm, fsm->nstage); 00438 } 00439 00445 static int saveHardLink(/*@special@*/ /*@partial@*/ IOSM_t fsm) 00446 /*@uses fsm->links, fsm->ix, fsm->sb, fsm->goal, fsm->nsuffix @*/ 00447 /*@defines fsm->li @*/ 00448 /*@releases fsm->path @*/ 00449 /*@globals h_errno, fileSystem, internalState @*/ 00450 /*@modifies fsm, fileSystem, internalState @*/ 00451 { 00452 struct stat * st = &fsm->sb; 00453 int rc = 0; 00454 int ix = -1; 00455 int j; 00456 00457 /* Find hard link set. */ 00458 for (fsm->li = fsm->links; fsm->li; fsm->li = fsm->li->next) { 00459 if (fsm->li->sb.st_ino == st->st_ino && fsm->li->sb.st_dev == st->st_dev) 00460 break; 00461 } 00462 00463 /* New hard link encountered, add new link to set. */ 00464 if (fsm->li == NULL) { 00465 fsm->li = xcalloc(1, sizeof(*fsm->li)); 00466 fsm->li->next = NULL; 00467 fsm->li->sb = *st; /* structure assignment */ 00468 fsm->li->nlink = (int) st->st_nlink; 00469 fsm->li->linkIndex = fsm->ix; 00470 fsm->li->createdPath = -1; 00471 00472 fsm->li->filex = xcalloc(st->st_nlink, sizeof(fsm->li->filex[0])); 00473 memset(fsm->li->filex, -1, (st->st_nlink * sizeof(fsm->li->filex[0]))); 00474 fsm->li->nsuffix = xcalloc(st->st_nlink, sizeof(*fsm->li->nsuffix)); 00475 00476 if (fsm->goal == IOSM_PKGBUILD) 00477 fsm->li->linksLeft = (int) st->st_nlink; 00478 if (fsm->goal == IOSM_PKGINSTALL) 00479 fsm->li->linksLeft = 0; 00480 00481 /*@-kepttrans@*/ 00482 fsm->li->next = fsm->links; 00483 /*@=kepttrans@*/ 00484 fsm->links = fsm->li; 00485 } 00486 00487 if (fsm->goal == IOSM_PKGBUILD) --fsm->li->linksLeft; 00488 fsm->li->filex[fsm->li->linksLeft] = fsm->ix; 00489 /*@-observertrans -dependenttrans@*/ 00490 fsm->li->nsuffix[fsm->li->linksLeft] = fsm->nsuffix; 00491 /*@=observertrans =dependenttrans@*/ 00492 if (fsm->goal == IOSM_PKGINSTALL) fsm->li->linksLeft++; 00493 00494 if (fsm->goal == IOSM_PKGBUILD) 00495 return (fsm->li->linksLeft > 0); 00496 00497 if (fsm->goal != IOSM_PKGINSTALL) 00498 return 0; 00499 00500 if (!(st->st_size || fsm->li->linksLeft == (int) st->st_nlink)) 00501 return 1; 00502 00503 /* Here come the bits, time to choose a non-skipped file name. */ 00504 { rpmfi fi = fsmGetFi(fsm); 00505 00506 for (j = fsm->li->linksLeft - 1; j >= 0; j--) { 00507 ix = fsm->li->filex[j]; 00508 if (ix < 0 || iosmFileActionSkipped(fi->actions[ix])) 00509 continue; 00510 break; 00511 } 00512 } 00513 00514 /* Are all links skipped or not encountered yet? */ 00515 if (ix < 0 || j < 0) 00516 return 1; /* XXX W2DO? */ 00517 00518 /* Save the non-skipped file name and map index. */ 00519 fsm->li->linkIndex = j; 00520 fsm->path = _free(fsm->path); 00521 fsm->ix = ix; 00522 rc = fsmNext(fsm, IOSM_MAP); 00523 return rc; 00524 } 00525 00531 static /*@null@*/ void * freeHardLink(/*@only@*/ /*@null@*/ struct hardLink_s * li) 00532 /*@modifies li @*/ 00533 { 00534 if (li) { 00535 li->nsuffix = _free(li->nsuffix); /* XXX elements are shared */ 00536 li->filex = _free(li->filex); 00537 } 00538 return _free(li); 00539 } 00540 00541 IOSM_t newFSM(void) 00542 { 00543 IOSM_t fsm = xcalloc(1, sizeof(*fsm)); 00544 return fsm; 00545 } 00546 00547 IOSM_t freeFSM(IOSM_t fsm) 00548 { 00549 if (fsm) { 00550 fsm->path = _free(fsm->path); 00551 while ((fsm->li = fsm->links) != NULL) { 00552 fsm->links = fsm->li->next; 00553 fsm->li->next = NULL; 00554 fsm->li = freeHardLink(fsm->li); 00555 } 00556 fsm->dnlx = _free(fsm->dnlx); 00557 fsm->ldn = _free(fsm->ldn); 00558 fsm->iter = mapFreeIterator(fsm->iter); 00559 } 00560 return _free(fsm); 00561 } 00562 00563 #if defined(SUPPORT_AR_PAYLOADS) 00564 static int arSetup(IOSM_t fsm, rpmfi fi) 00565 /*@modifies fsm @*/ 00566 { 00567 const char * path; 00568 char * t; 00569 size_t lmtablen = 0; 00570 size_t nb; 00571 00572 /* Calculate size of ar(1) long member table. */ 00573 if ((fi = rpmfiInit(fi, 0)) != NULL) 00574 while (rpmfiNext(fi) >= 0) { 00575 #ifdef NOTYET 00576 if (fi->apath) { 00577 const char * apath = NULL; 00578 (void) urlPath(fi->apath[ix], &apath); 00579 path = apath + fi->striplen; 00580 } else 00581 #endif 00582 path = rpmfiBN(fi); 00583 if ((nb = strlen(path)) < 15) 00584 continue; 00585 lmtablen += nb + 1; /* trailing \n */ 00586 } 00587 00588 /* Anything to do? */ 00589 if (lmtablen == 0) 00590 return 0; 00591 00592 /* Create and load ar(1) long member table. */ 00593 fsm->lmtab = t = xmalloc(lmtablen + 1); /* trailing \0 */ 00594 fsm->lmtablen = lmtablen; 00595 fsm->lmtaboff = 0; 00596 if ((fi = rpmfiInit(fi, 0)) != NULL) 00597 while (rpmfiNext(fi) >= 0) { 00598 #ifdef NOTYET 00599 if (fi->apath) { 00600 const char * apath = NULL; 00601 (void) urlPath(fi->apath[ix], &apath); 00602 path = apath + fi->striplen; 00603 } else 00604 #endif 00605 path = rpmfiBN(fi); 00606 if ((nb = strlen(path)) < 15) 00607 continue; 00608 t = stpcpy(t, path); 00609 *t++ = '\n'; 00610 } 00611 *t = '\0'; 00612 00613 return 0; 00614 } 00615 #endif 00616 00617 int fsmSetup(void * _fsm, iosmFileStage goal, const char * afmt, 00618 const void * _ts, const void * _fi, FD_t cfd, 00619 unsigned int * archiveSize, const char ** failedFile) 00620 { 00621 IOSM_t fsm = _fsm; 00622 /*@-castexpose@*/ 00623 const rpmts ts = (const rpmts) _ts; 00624 const rpmfi fi = (const rpmfi) _fi; 00625 /*@=castexpose@*/ 00626 #if defined(_USE_RPMTE) 00627 int reverse = (rpmteType(fi->te) == TR_REMOVED && fi->action != FA_COPYOUT); 00628 int adding = (rpmteType(fi->te) == TR_ADDED); 00629 #else 00630 int reverse = 0; /* XXX HACK: devise alternative means */ 00631 int adding = 1; /* XXX HACK: devise alternative means */ 00632 #endif 00633 size_t pos = 0; 00634 int rc, ec = 0; 00635 00636 fsm->debug = _fsm_debug; 00637 fsm->multithreaded = _fsm_threads; 00638 fsm->adding = adding; 00639 00640 /*@+voidabstract -nullpass@*/ 00641 if (fsm->debug < 0) 00642 fprintf(stderr, "--> fsmSetup(%p, 0x%x, \"%s\", %p, %p, %p, %p, %p)\n", fsm, goal, afmt, (void *)ts, fi, cfd, archiveSize, failedFile); 00643 /*@=voidabstract =nullpass@*/ 00644 00645 _iosmNext = &fsmNext; 00646 if (fsm->headerRead == NULL) { 00647 if (afmt != NULL && (!strcmp(afmt, "tar") || !strcmp(afmt, "ustar"))) { 00648 if (fsm->debug < 0) 00649 fprintf(stderr, "\ttar vectors set\n"); 00650 fsm->headerRead = &tarHeaderRead; 00651 fsm->headerWrite = &tarHeaderWrite; 00652 fsm->trailerWrite = &tarTrailerWrite; 00653 fsm->blksize = TAR_BLOCK_SIZE; 00654 } else 00655 #if defined(SUPPORT_AR_PAYLOADS) 00656 if (afmt != NULL && !strcmp(afmt, "ar")) { 00657 if (fsm->debug < 0) 00658 fprintf(stderr, "\tar vectors set\n"); 00659 fsm->headerRead = &arHeaderRead; 00660 fsm->headerWrite = &arHeaderWrite; 00661 fsm->trailerWrite = &arTrailerWrite; 00662 fsm->blksize = 2; 00663 if (goal == IOSM_PKGBUILD || goal == IOSM_PKGERASE) 00664 (void) arSetup(fsm, fi); 00665 } else 00666 #endif 00667 { 00668 if (fsm->debug < 0) 00669 fprintf(stderr, "\tcpio vectors set\n"); 00670 fsm->headerRead = &cpioHeaderRead; 00671 fsm->headerWrite = &cpioHeaderWrite; 00672 fsm->trailerWrite = &cpioTrailerWrite; 00673 fsm->blksize = 4; 00674 } 00675 } 00676 00677 fsm->goal = goal; 00678 if (cfd != NULL) { 00679 /*@-assignexpose -castexpose @*/ 00680 fsm->cfd = fdLink(cfd, "persist (fsm)"); 00681 /*@=assignexpose =castexpose @*/ 00682 pos = fdGetCpioPos(fsm->cfd); 00683 fdSetCpioPos(fsm->cfd, 0); 00684 } 00685 /*@-mods@*/ /* LCL: avoid void * _ts/_fi annotations for now. */ 00686 fsm->iter = mapInitIterator(fi, reverse); 00687 /*@-assignexpose -castexpose @*/ 00688 fsm->iter->ts = rpmtsLink(ts, "mapIterator"); 00689 /*@=assignexpose =castexpose @*/ 00690 fsm->nofcontexts = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONTEXTS); 00691 /*@=mods@*/ 00692 fsm->nofdigests = 00693 (ts != NULL && !(rpmtsFlags(ts) & RPMTRANS_FLAG_NOFDIGESTS)) 00694 ? 0 : 1; 00695 #define _tsmask (RPMTRANS_FLAG_PKGCOMMIT | RPMTRANS_FLAG_COMMIT) 00696 fsm->commit = ((ts && (rpmtsFlags(ts) & _tsmask) && 00697 fsm->goal != IOSM_PKGCOMMIT) ? 0 : 1); 00698 #undef _tsmask 00699 00700 if (fsm->goal == IOSM_PKGINSTALL || fsm->goal == IOSM_PKGBUILD) { 00701 void * ptr; 00702 fi->archivePos = 0; 00703 ptr = rpmtsNotify(ts, fi->te, 00704 RPMCALLBACK_INST_START, fi->archivePos, fi->archiveSize); 00705 } 00706 00707 /*@-assignexpose@*/ 00708 fsm->archiveSize = archiveSize; 00709 if (fsm->archiveSize) 00710 *fsm->archiveSize = 0; 00711 fsm->failedFile = failedFile; 00712 if (fsm->failedFile) 00713 *fsm->failedFile = NULL; 00714 /*@=assignexpose@*/ 00715 00716 memset(fsm->sufbuf, 0, sizeof(fsm->sufbuf)); 00717 if (fsm->goal == IOSM_PKGINSTALL) { 00718 if (ts && rpmtsGetTid(ts) != (rpmuint32_t)-1) 00719 sprintf(fsm->sufbuf, ";%08x", (unsigned)rpmtsGetTid(ts)); 00720 } 00721 00722 ec = fsm->rc = 0; 00723 /*@-mods@*/ /* LCL: avoid void * _fsm annotation for now. */ 00724 rc = fsmUNSAFE(fsm, IOSM_CREATE); 00725 /*@=mods@*/ 00726 if (rc && !ec) ec = rc; 00727 00728 /*@-mods@*/ /* LCL: avoid void * _fsm annotation for now. */ 00729 rc = fsmUNSAFE(fsm, fsm->goal); 00730 /*@=mods@*/ 00731 if (rc && !ec) ec = rc; 00732 00733 if (fsm->archiveSize && ec == 0) 00734 *fsm->archiveSize = (fdGetCpioPos(fsm->cfd) - pos); 00735 00736 /*@-nullstate@*/ /* FIX: *fsm->failedFile may be NULL */ 00737 return ec; 00738 /*@=nullstate@*/ 00739 } 00740 00741 int fsmTeardown(void * _fsm) 00742 { 00743 IOSM_t fsm = _fsm; 00744 int rc = fsm->rc; 00745 00746 if (fsm->debug < 0) 00747 fprintf(stderr, "--> fsmTeardown(%p)\n", fsm); 00748 if (!rc) 00749 rc = fsmUNSAFE(fsm, IOSM_DESTROY); 00750 00751 (void) rpmswAdd(rpmtsOp(fsmGetTs(fsm), RPMTS_OP_DIGEST), 00752 &fsm->op_digest); 00753 00754 fsm->lmtab = _free(fsm->lmtab); 00755 (void)rpmtsFree(fsm->iter->ts); 00756 fsm->iter->ts = NULL; 00757 fsm->iter = mapFreeIterator(fsm->iter); 00758 if (fsm->cfd != NULL) { 00759 /*@-refcounttrans@*/ /* FIX: XfdFree annotation */ 00760 fsm->cfd = fdFree(fsm->cfd, "persist (fsm)"); 00761 /*@=refcounttrans@*/ 00762 fsm->cfd = NULL; 00763 } 00764 fsm->failedFile = NULL; 00765 return rc; 00766 } 00767 00768 /* 00769 * Set file security context (if not disabled). 00770 * @param fsm file state machine data 00771 * @return 0 always 00772 */ 00773 static int fsmMapFContext(IOSM_t fsm) 00774 /*@modifies fsm @*/ 00775 { 00776 fsm->fcontext = NULL; 00777 if (!fsm->nofcontexts) { 00778 security_context_t scon = NULL; 00779 /*@-moduncon@*/ 00780 int xx = matchpathcon(fsm->path, fsm->sb.st_mode, &scon); 00781 /*@=moduncon@*/ 00782 00783 if (!xx && scon != NULL) 00784 fsm->fcontext = scon; 00785 #ifdef DYING /* XXX SELinux file contexts not set from package content. */ 00786 else { 00787 rpmfi fi = fsmGetFi(fsm); 00788 int i = fsm->ix; 00789 00790 /* Get file security context from package. */ 00791 if (fi && i >= 0 && i < (int)fi->fc) 00792 fsm->fcontext = (fi->fcontexts ? fi->fcontexts[i] : NULL); 00793 } 00794 #endif 00795 } 00796 return 0; 00797 } 00798 00799 int fsmMapPath(IOSM_t fsm) 00800 { 00801 rpmfi fi = fsmGetFi(fsm); /* XXX const except for fstates */ 00802 int teAdding = fsm->adding; 00803 int rc = 0; 00804 int i = fsm->ix; 00805 00806 fsm->osuffix = NULL; 00807 fsm->nsuffix = NULL; 00808 fsm->astriplen = 0; 00809 fsm->action = FA_UNKNOWN; 00810 fsm->mapFlags = fi->mapflags; 00811 00812 if (fi && i >= 0 && i < (int)fi->fc) { 00813 00814 fsm->astriplen = fi->astriplen; 00815 fsm->action = (fi->actions ? fi->actions[i] : fi->action); 00816 fsm->fflags = (fi->fflags ? fi->fflags[i] : fi->flags); 00817 fsm->mapFlags = (fi->fmapflags ? fi->fmapflags[i] : fi->mapflags); 00818 00819 /* src rpms have simple base name in payload. */ 00820 fsm->dirName = fi->dnl[fi->dil[i]]; 00821 fsm->baseName = fi->bnl[i]; 00822 00823 switch (fsm->action) { 00824 case FA_SKIP: 00825 break; 00826 case FA_UNKNOWN: 00827 break; 00828 00829 case FA_COPYOUT: 00830 break; 00831 case FA_COPYIN: 00832 case FA_CREATE: 00833 assert(teAdding); 00834 break; 00835 00836 case FA_SKIPNSTATE: 00837 if (fi->fstates && teAdding) 00838 fi->fstates[i] = RPMFILE_STATE_NOTINSTALLED; 00839 break; 00840 00841 case FA_SKIPNETSHARED: 00842 if (fi->fstates && teAdding) 00843 fi->fstates[i] = RPMFILE_STATE_NETSHARED; 00844 break; 00845 00846 case FA_SKIPCOLOR: 00847 if (fi->fstates && teAdding) 00848 fi->fstates[i] = RPMFILE_STATE_WRONGCOLOR; 00849 break; 00850 00851 case FA_BACKUP: 00852 if (!(fsm->fflags & RPMFILE_GHOST)) /* XXX Don't if %ghost file. */ 00853 fsm->osuffix = (teAdding ? SUFFIX_RPMORIG : SUFFIX_RPMSAVE); 00854 break; 00855 00856 case FA_ALTNAME: 00857 assert(teAdding); 00858 if (!(fsm->fflags & RPMFILE_GHOST)) /* XXX Don't if %ghost file. */ 00859 fsm->nsuffix = SUFFIX_RPMNEW; 00860 break; 00861 00862 case FA_SAVE: 00863 assert(teAdding); 00864 if (!(fsm->fflags & RPMFILE_GHOST)) /* XXX Don't if %ghost file. */ 00865 fsm->osuffix = SUFFIX_RPMSAVE; 00866 break; 00867 case FA_ERASE: 00868 #if 0 /* XXX is this a genhdlist fix? */ 00869 assert(rpmteType(fi->te) == TR_REMOVED); 00870 #endif 00871 /* 00872 * XXX TODO: %ghost probably shouldn't be removed, but that changes 00873 * legacy rpm behavior. 00874 */ 00875 break; 00876 default: 00877 break; 00878 } 00879 00880 if ((fsm->mapFlags & IOSM_MAP_PATH) || fsm->nsuffix) { 00881 const struct stat * st = &fsm->sb; 00882 fsm->path = _free(fsm->path); 00883 fsm->path = fsmFsPath(fsm, st, fsm->subdir, 00884 (fsm->suffix ? fsm->suffix : fsm->nsuffix)); 00885 } 00886 } 00887 return rc; 00888 } 00889 00890 int fsmMapAttrs(IOSM_t fsm) 00891 { 00892 struct stat * st = &fsm->sb; 00893 rpmfi fi = fsmGetFi(fsm); 00894 int i = fsm->ix; 00895 00896 if (fi && i >= 0 && i < (int) fi->fc) { 00897 mode_t perms = (S_ISDIR(st->st_mode) ? fi->dperms : fi->fperms); 00898 mode_t finalMode = (fi->fmodes ? (mode_t)fi->fmodes[i] : perms); 00899 dev_t finalRdev = (dev_t)(fi->frdevs ? fi->frdevs[i] : 0); 00900 rpmuint32_t finalMtime = (fi->fmtimes ? fi->fmtimes[i] : 0); 00901 uid_t uid = fi->uid; 00902 gid_t gid = fi->gid; 00903 00904 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* no-owner-group-on-srpm-install */ 00905 /* Make sure OpenPKG/Mandriva RPM does not try to set file owner/group on files during 00906 installation of _source_ RPMs. Instead, let it use the current 00907 run-time owner/group, because most of the time the owner/group in 00908 the source RPM (which is the owner/group of the files as staying on 00909 the package author system) is not existing on the target system, of 00910 course. */ 00911 #endif 00912 if (fi->fuser && unameToUid(fi->fuser[i], &uid)) { 00913 #if defined(RPM_VENDOR_OPENPKG) ||defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* no-owner-group-on-srpm-install */ 00914 if (!fi->isSource) { 00915 #endif 00916 if (fsm->goal == IOSM_PKGINSTALL) 00917 rpmlog(RPMLOG_WARNING, 00918 _("user %s does not exist - using root\n"), fi->fuser[i]); 00919 uid = 0; 00920 finalMode &= ~S_ISUID; /* turn off suid bit */ 00921 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* no-owner-group-on-srpm-install */ 00922 } 00923 #endif 00924 } 00925 00926 if (fi->fgroup && gnameToGid(fi->fgroup[i], &gid)) { 00927 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* no-owner-group-on-srpm-install */ 00928 if (!fi->isSource) { 00929 #endif 00930 if (fsm->goal == IOSM_PKGINSTALL) 00931 rpmlog(RPMLOG_WARNING, 00932 _("group %s does not exist - using root\n"), fi->fgroup[i]); 00933 gid = 0; 00934 finalMode &= ~S_ISGID; /* turn off sgid bit */ 00935 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* no-owner-group-on-srpm-install */ 00936 } 00937 #endif 00938 } 00939 00940 if (fsm->mapFlags & IOSM_MAP_MODE) 00941 st->st_mode = (st->st_mode & S_IFMT) | (finalMode & ~S_IFMT); 00942 if (fsm->mapFlags & IOSM_MAP_TYPE) { 00943 st->st_mode = (st->st_mode & ~S_IFMT) | (finalMode & S_IFMT); 00944 if ((S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) 00945 && st->st_nlink == 0) 00946 st->st_nlink = 1; 00947 st->st_rdev = finalRdev; 00948 st->st_mtime = finalMtime; 00949 } 00950 if (fsm->mapFlags & IOSM_MAP_UID) 00951 st->st_uid = uid; 00952 if (fsm->mapFlags & IOSM_MAP_GID) 00953 st->st_gid = gid; 00954 00955 /* 00956 * Set file digest (if not disabled). 00957 */ 00958 if (!fsm->nofdigests) { 00959 fsm->fdigestalgo = fi->digestalgo; 00960 fsm->fdigest = (fi->fdigests ? fi->fdigests[i] : NULL); 00961 fsm->digestlen = fi->digestlen; 00962 fsm->digest = (fi->digests ? (fi->digests + (fsm->digestlen * i)) : NULL); 00963 } else { 00964 fsm->fdigestalgo = 0; 00965 fsm->fdigest = NULL; 00966 fsm->digestlen = 0; 00967 fsm->digest = NULL; 00968 } 00969 } 00970 return 0; 00971 } 00972 00978 /*@-compdef@*/ 00979 static int extractRegular(/*@special@*/ IOSM_t fsm) 00980 /*@uses fsm->fdigest, fsm->digest, fsm->sb, fsm->wfd @*/ 00981 /*@globals h_errno, fileSystem, internalState @*/ 00982 /*@modifies fsm, fileSystem, internalState @*/ 00983 { 00984 const struct stat * st = &fsm->sb; 00985 size_t left = (size_t) st->st_size; 00986 int rc = 0; 00987 int xx; 00988 00989 rc = fsmNext(fsm, IOSM_WOPEN); 00990 if (rc) 00991 goto exit; 00992 00993 if (st->st_size > 0 && (fsm->fdigest != NULL || fsm->digest != NULL)) 00994 fdInitDigest(fsm->wfd, fsm->fdigestalgo, 0); 00995 00996 while (left) { 00997 00998 fsm->wrlen = (left > fsm->wrsize ? fsm->wrsize : left); 00999 rc = fsmNext(fsm, IOSM_DREAD); 01000 if (rc) 01001 goto exit; 01002 01003 rc = fsmNext(fsm, IOSM_WRITE); 01004 if (rc) 01005 goto exit; 01006 01007 left -= fsm->wrnb; 01008 01009 /* Notify iff progress, completion is done elsewhere */ 01010 if (!rc && left) 01011 (void) fsmNext(fsm, IOSM_NOTIFY); 01012 } 01013 01014 xx = fsync(Fileno(fsm->wfd)); 01015 01016 if (st->st_size > 0 && (fsm->fdigest || fsm->digest)) { 01017 void * digest = NULL; 01018 int asAscii = (fsm->digest == NULL ? 1 : 0); 01019 01020 (void) Fflush(fsm->wfd); 01021 fdFiniDigest(fsm->wfd, fsm->fdigestalgo, &digest, NULL, asAscii); 01022 01023 if (digest == NULL) { 01024 rc = IOSMERR_DIGEST_MISMATCH; 01025 goto exit; 01026 } 01027 01028 if (fsm->digest != NULL) { 01029 if (memcmp(digest, fsm->digest, fsm->digestlen)) 01030 rc = IOSMERR_DIGEST_MISMATCH; 01031 } else { 01032 if (strcmp(digest, fsm->fdigest)) 01033 rc = IOSMERR_DIGEST_MISMATCH; 01034 } 01035 digest = _free(digest); 01036 } 01037 01038 exit: 01039 (void) fsmNext(fsm, IOSM_WCLOSE); 01040 return rc; 01041 } 01042 /*@=compdef@*/ 01043 01050 /*@-compdef -compmempass@*/ 01051 static int writeFile(/*@special@*/ /*@partial@*/ IOSM_t fsm, int writeData) 01052 /*@uses fsm->path, fsm->opath, fsm->sb, fsm->osb, fsm->cfd @*/ 01053 /*@globals h_errno, fileSystem, internalState @*/ 01054 /*@modifies fsm, fileSystem, internalState @*/ 01055 { 01056 const char * path = fsm->path; 01057 const char * opath = fsm->opath; 01058 struct stat * st = &fsm->sb; 01059 struct stat * ost = &fsm->osb; 01060 size_t left; 01061 int xx; 01062 int rc; 01063 01064 st->st_size = (writeData ? ost->st_size : 0); 01065 01066 if (S_ISDIR(st->st_mode)) { 01067 st->st_size = 0; 01068 } else if (S_ISLNK(st->st_mode)) { 01069 /* 01070 * While linux puts the size of a symlink in the st_size field, 01071 * I don't think that's a specified standard. 01072 */ 01073 /* XXX NUL terminated result in fsm->rdbuf, len in fsm->rdnb. */ 01074 rc = fsmUNSAFE(fsm, IOSM_READLINK); 01075 if (rc) goto exit; 01076 st->st_size = fsm->rdnb; 01077 fsm->lpath = xstrdup(fsm->rdbuf); /* XXX save readlink return. */ 01078 } 01079 01080 if (fsm->mapFlags & IOSM_MAP_ABSOLUTE) { 01081 size_t nb= strlen(fsm->dirName) + strlen(fsm->baseName) + sizeof("."); 01082 char * t = alloca(nb); 01083 *t = '\0'; 01084 fsm->path = t; 01085 if (fsm->mapFlags & IOSM_MAP_ADDDOT) 01086 *t++ = '.'; 01087 t = stpcpy( stpcpy(t, fsm->dirName), fsm->baseName); 01088 } else if (fsm->mapFlags & IOSM_MAP_PATH) { 01089 rpmfi fi = fsmGetFi(fsm); 01090 if (fi->apath) { 01091 const char * apath = NULL; 01092 (void) urlPath(fi->apath[fsm->ix], &apath); 01093 fsm->path = apath + fi->striplen; 01094 } else 01095 fsm->path = fi->bnl[fsm->ix]; 01096 } 01097 01098 rc = fsmNext(fsm, IOSM_HWRITE); 01099 fsm->path = path; 01100 if (rc) goto exit; 01101 01102 if (writeData && S_ISREG(st->st_mode)) { 01103 #if defined(HAVE_MMAP) 01104 char * rdbuf = NULL; 01105 void * mapped = (void *)-1; 01106 size_t nmapped = 0; 01107 /* XXX 128 Mb resource cap for top(1) scrutiny, MADV_DONTNEED better. */ 01108 int use_mmap = (st->st_size <= 0x07ffffff); 01109 #endif 01110 01111 rc = fsmNext(fsm, IOSM_ROPEN); 01112 if (rc) goto exit; 01113 01114 /* XXX unbuffered mmap generates *lots* of fdio debugging */ 01115 #if defined(HAVE_MMAP) 01116 if (use_mmap) { 01117 mapped = mmap(NULL, st->st_size, PROT_READ, MAP_SHARED, Fileno(fsm->rfd), 0); 01118 if (mapped != (void *)-1) { 01119 rdbuf = fsm->rdbuf; 01120 fsm->rdbuf = (char *) mapped; 01121 fsm->rdlen = nmapped = st->st_size; 01122 #if defined(HAVE_MADVISE) && defined(MADV_DONTNEED) 01123 xx = madvise(mapped, nmapped, MADV_DONTNEED); 01124 #endif 01125 } 01126 } 01127 #endif 01128 01129 left = st->st_size; 01130 01131 while (left) { 01132 #if defined(HAVE_MMAP) 01133 if (mapped != (void *)-1) { 01134 fsm->rdnb = nmapped; 01135 } else 01136 #endif 01137 { 01138 fsm->rdlen = (left > fsm->rdsize ? fsm->rdsize : left), 01139 rc = fsmNext(fsm, IOSM_READ); 01140 if (rc) goto exit; 01141 } 01142 01143 /* XXX DWRITE uses rdnb for I/O length. */ 01144 rc = fsmNext(fsm, IOSM_DWRITE); 01145 if (rc) goto exit; 01146 01147 left -= fsm->wrnb; 01148 } 01149 01150 #if defined(HAVE_MMAP) 01151 if (mapped != (void *)-1) { 01152 /* XXX splint misses size_t 2nd arg. */ 01153 /*@i@*/ xx = msync(mapped, nmapped, MS_ASYNC); 01154 #if defined(HAVE_MADVISE) && defined(MADV_DONTNEED) 01155 xx = madvise(mapped, nmapped, MADV_DONTNEED); 01156 #endif 01157 xx = munmap(mapped, nmapped); 01158 fsm->rdbuf = rdbuf; 01159 } else 01160 #endif 01161 xx = fsync(Fileno(fsm->rfd)); 01162 01163 } 01164 01165 rc = fsmNext(fsm, IOSM_PAD); 01166 if (rc) goto exit; 01167 01168 rc = 0; 01169 01170 exit: 01171 if (fsm->rfd != NULL) 01172 (void) fsmNext(fsm, IOSM_RCLOSE); 01173 /*@-dependenttrans@*/ 01174 fsm->opath = opath; 01175 fsm->path = path; 01176 /*@=dependenttrans@*/ 01177 return rc; 01178 } 01179 /*@=compdef =compmempass@*/ 01180 01186 static int writeLinkedFile(/*@special@*/ /*@partial@*/ IOSM_t fsm) 01187 /*@uses fsm->path, fsm->nsuffix, fsm->ix, fsm->li, fsm->failedFile @*/ 01188 /*@globals h_errno, fileSystem, internalState @*/ 01189 /*@modifies fsm, fileSystem, internalState @*/ 01190 { 01191 const char * path = fsm->path; 01192 const char * lpath = fsm->lpath; 01193 const char * nsuffix = fsm->nsuffix; 01194 int iterIndex = fsm->ix; 01195 int ec = 0; 01196 int rc; 01197 int i; 01198 const char * linkpath = NULL; 01199 int firstfile = 1; 01200 01201 fsm->path = NULL; 01202 fsm->lpath = NULL; 01203 fsm->nsuffix = NULL; 01204 fsm->ix = -1; 01205 01206 for (i = fsm->li->nlink - 1; i >= 0; i--) { 01207 01208 if (fsm->li->filex[i] < 0) continue; 01209 01210 fsm->ix = fsm->li->filex[i]; 01211 /*@-compdef@*/ 01212 rc = fsmNext(fsm, IOSM_MAP); 01213 /*@=compdef@*/ 01214 01215 /* XXX tar and cpio have to do things differently. */ 01216 if (fsm->headerWrite == tarHeaderWrite) { 01217 if (firstfile) { 01218 const char * apath = NULL; 01219 char *t; 01220 (void) urlPath(fsm->path, &apath); 01221 /* Remove the buildroot prefix. */ 01222 t = xmalloc(sizeof(".") + strlen(apath + fsm->astriplen)); 01223 (void) stpcpy( stpcpy(t, "."), apath + fsm->astriplen); 01224 linkpath = t; 01225 firstfile = 0; 01226 } else 01227 fsm->lpath = linkpath; 01228 01229 /* Write data after first link for tar. */ 01230 rc = writeFile(fsm, (fsm->lpath == NULL)); 01231 } else { 01232 /* Write data after last link for cpio. */ 01233 rc = writeFile(fsm, (i == 0)); 01234 } 01235 if (fsm->failedFile && rc != 0 && *fsm->failedFile == NULL) { 01236 ec = rc; 01237 *fsm->failedFile = xstrdup(fsm->path); 01238 } 01239 01240 fsm->path = _free(fsm->path); 01241 fsm->li->filex[i] = -1; 01242 } 01243 01244 /*@-dependenttrans@*/ 01245 linkpath = _free(linkpath); 01246 /*@=dependenttrans@*/ 01247 fsm->ix = iterIndex; 01248 fsm->nsuffix = nsuffix; 01249 fsm->lpath = lpath; 01250 fsm->path = path; 01251 return ec; 01252 } 01253 01259 /*@-compdef@*/ 01260 static int fsmMakeLinks(/*@special@*/ /*@partial@*/ IOSM_t fsm) 01261 /*@uses fsm->path, fsm->opath, fsm->nsuffix, fsm->ix, fsm->li @*/ 01262 /*@globals h_errno, fileSystem, internalState @*/ 01263 /*@modifies fsm, fileSystem, internalState @*/ 01264 { 01265 const char * path = fsm->path; 01266 const char * opath = fsm->opath; 01267 const char * nsuffix = fsm->nsuffix; 01268 int iterIndex = fsm->ix; 01269 int ec = 0; 01270 int rc; 01271 int i; 01272 01273 fsm->path = NULL; 01274 fsm->opath = NULL; 01275 fsm->nsuffix = NULL; 01276 fsm->ix = -1; 01277 01278 fsm->ix = fsm->li->filex[fsm->li->createdPath]; 01279 rc = fsmNext(fsm, IOSM_MAP); 01280 fsm->opath = fsm->path; 01281 fsm->path = NULL; 01282 for (i = 0; i < fsm->li->nlink; i++) { 01283 if (fsm->li->filex[i] < 0) continue; 01284 if (fsm->li->createdPath == i) continue; 01285 01286 fsm->ix = fsm->li->filex[i]; 01287 fsm->path = _free(fsm->path); 01288 rc = fsmNext(fsm, IOSM_MAP); 01289 if (iosmFileActionSkipped(fsm->action)) continue; 01290 01291 rc = fsmUNSAFE(fsm, IOSM_VERIFY); 01292 if (!rc) continue; 01293 if (!(rc == IOSMERR_ENOENT)) break; 01294 01295 /* XXX link(fsm->opath, fsm->path) */ 01296 rc = fsmNext(fsm, IOSM_LINK); 01297 if (fsm->failedFile && rc != 0 && *fsm->failedFile == NULL) { 01298 ec = rc; 01299 *fsm->failedFile = xstrdup(fsm->path); 01300 } 01301 01302 fsm->li->linksLeft--; 01303 } 01304 fsm->path = _free(fsm->path); 01305 fsm->opath = _free(fsm->opath); 01306 01307 fsm->ix = iterIndex; 01308 fsm->nsuffix = nsuffix; 01309 fsm->path = path; 01310 fsm->opath = opath; 01311 return ec; 01312 } 01313 /*@=compdef@*/ 01314 01320 /*@-compdef@*/ 01321 static int fsmCommitLinks(/*@special@*/ /*@partial@*/ IOSM_t fsm) 01322 /*@uses fsm->path, fsm->nsuffix, fsm->ix, fsm->sb, 01323 fsm->li, fsm->links @*/ 01324 /*@globals h_errno, fileSystem, internalState @*/ 01325 /*@modifies fsm, fileSystem, internalState @*/ 01326 { 01327 const char * path = fsm->path; 01328 const char * nsuffix = fsm->nsuffix; 01329 int iterIndex = fsm->ix; 01330 struct stat * st = &fsm->sb; 01331 int rc = 0; 01332 int i; 01333 01334 fsm->path = NULL; 01335 fsm->nsuffix = NULL; 01336 fsm->ix = -1; 01337 01338 for (fsm->li = fsm->links; fsm->li; fsm->li = fsm->li->next) { 01339 if (fsm->li->sb.st_ino == st->st_ino && fsm->li->sb.st_dev == st->st_dev) 01340 break; 01341 } 01342 01343 for (i = 0; i < fsm->li->nlink; i++) { 01344 if (fsm->li->filex[i] < 0) continue; 01345 fsm->ix = fsm->li->filex[i]; 01346 rc = fsmNext(fsm, IOSM_MAP); 01347 if (!iosmFileActionSkipped(fsm->action)) 01348 rc = fsmNext(fsm, IOSM_COMMIT); 01349 fsm->path = _free(fsm->path); 01350 fsm->li->filex[i] = -1; 01351 } 01352 01353 fsm->ix = iterIndex; 01354 fsm->nsuffix = nsuffix; 01355 fsm->path = path; 01356 return rc; 01357 } 01358 /*@=compdef@*/ 01359 01365 static int fsmRmdirs(/*@special@*/ /*@partial@*/ IOSM_t fsm) 01366 /*@uses fsm->path, fsm->dnlx, fsm->ldn, fsm->rdbuf, fsm->iter @*/ 01367 /*@globals h_errno, fileSystem, internalState @*/ 01368 /*@modifies fsm, fileSystem, internalState @*/ 01369 { 01370 const char * path = fsm->path; 01371 void * dnli = dnlInitIterator(fsm, 1); 01372 char * dn = fsm->rdbuf; 01373 int dc = dnlCount(dnli); 01374 int rc = 0; 01375 01376 fsm->path = NULL; 01377 dn[0] = '\0'; 01378 /*@-observertrans -dependenttrans@*/ 01379 if (fsm->ldn != NULL && fsm->dnlx != NULL) 01380 while ((fsm->path = dnlNextIterator(dnli)) != NULL) { 01381 size_t dnlen = strlen(fsm->path); 01382 char * te; 01383 01384 dc = dnlIndex(dnli); 01385 if (fsm->dnlx[dc] < 1 || (size_t)fsm->dnlx[dc] >= dnlen) 01386 continue; 01387 01388 /* Copy to avoid const on fsm->path. */ 01389 te = stpcpy(dn, fsm->path) - 1; 01390 fsm->path = dn; 01391 01392 /* Remove generated directories. */ 01393 /*@-usereleased@*/ /* LCL: te used after release? */ 01394 do { 01395 if (*te == '/') { 01396 *te = '\0'; 01397 /*@-compdef@*/ 01398 rc = fsmNext(fsm, IOSM_RMDIR); 01399 /*@=compdef@*/ 01400 *te = '/'; 01401 } 01402 if (rc) 01403 /*@innerbreak@*/ break; 01404 te--; 01405 } while ((te - fsm->path) > fsm->dnlx[dc]); 01406 /*@=usereleased@*/ 01407 } 01408 dnli = dnlFreeIterator(dnli); 01409 /*@=observertrans =dependenttrans@*/ 01410 01411 fsm->path = path; 01412 return rc; 01413 } 01414 01420 static int fsmMkdirs(/*@special@*/ /*@partial@*/ IOSM_t fsm) 01421 /*@uses fsm->path, fsm->sb, fsm->osb, fsm->rdbuf, fsm->iter, 01422 fsm->ldn, fsm->ldnlen, fsm->ldnalloc @*/ 01423 /*@defines fsm->dnlx, fsm->ldn @*/ 01424 /*@globals h_errno, fileSystem, internalState @*/ 01425 /*@modifies fsm, fileSystem, internalState @*/ 01426 { 01427 struct stat * st = &fsm->sb; 01428 struct stat * ost = &fsm->osb; 01429 const char * path = fsm->path; 01430 mode_t st_mode = st->st_mode; 01431 void * dnli = dnlInitIterator(fsm, 0); 01432 char * dn = fsm->rdbuf; 01433 int dc = dnlCount(dnli); 01434 int rc = 0; 01435 size_t i; 01436 01437 fsm->path = NULL; 01438 01439 dn[0] = '\0'; 01440 fsm->dnlx = (dc ? xcalloc(dc, sizeof(*fsm->dnlx)) : NULL); 01441 /*@-observertrans -dependenttrans@*/ 01442 if (fsm->dnlx != NULL) 01443 while ((fsm->path = dnlNextIterator(dnli)) != NULL) { 01444 size_t dnlen = strlen(fsm->path); 01445 char * te; 01446 01447 dc = dnlIndex(dnli); 01448 if (dc < 0) continue; 01449 fsm->dnlx[dc] = (unsigned short) dnlen; 01450 if (dnlen <= 1) 01451 continue; 01452 01453 /*@-compdef -nullpass@*/ /* FIX: fsm->ldn not defined ??? */ 01454 if (dnlen <= fsm->ldnlen && !strcmp(fsm->path, fsm->ldn)) 01455 continue; 01456 /*@=compdef =nullpass@*/ 01457 01458 /* Copy to avoid const on fsm->path. */ 01459 (void) stpcpy(dn, fsm->path); 01460 fsm->path = dn; 01461 01462 /* Assume '/' directory exists, "mkdir -p" for others if non-existent */ 01463 (void) urlPath(dn, (const char **)&te); 01464 for (i = 1, te++; *te != '\0'; te++, i++) { 01465 if (*te != '/') 01466 /*@innercontinue@*/ continue; 01467 01468 *te = '\0'; 01469 01470 /* Already validated? */ 01471 /*@-usedef -compdef -nullpass -nullderef@*/ 01472 if (i < fsm->ldnlen && 01473 (fsm->ldn[i] == '/' || fsm->ldn[i] == '\0') && 01474 !strncmp(fsm->path, fsm->ldn, i)) 01475 { 01476 *te = '/'; 01477 /* Move pre-existing path marker forward. */ 01478 fsm->dnlx[dc] = (te - dn); 01479 /*@innercontinue@*/ continue; 01480 } 01481 /*@=usedef =compdef =nullpass =nullderef@*/ 01482 01483 /* Validate next component of path. */ 01484 rc = fsmUNSAFE(fsm, IOSM_LSTAT); 01485 *te = '/'; 01486 01487 /* Directory already exists? */ 01488 if (rc == 0 && S_ISDIR(ost->st_mode)) { 01489 /* Move pre-existing path marker forward. */ 01490 fsm->dnlx[dc] = (te - dn); 01491 } else if (rc == IOSMERR_ENOENT) { 01492 rpmfi fi = fsmGetFi(fsm); 01493 *te = '\0'; 01494 st->st_mode = S_IFDIR | (fi->dperms & 07777); 01495 rc = fsmNext(fsm, IOSM_MKDIR); 01496 if (!rc) { 01497 security_context_t scon = NULL; 01498 /* XXX FIXME? only new dir will have context set. */ 01499 /* Get file security context from patterns. */ 01500 /*@-moduncon@*/ 01501 if (!fsm->nofcontexts 01502 && !matchpathcon(fsm->path, st->st_mode, &scon) 01503 && scon != NULL) 01504 /*@=moduncon@*/ 01505 { 01506 fsm->fcontext = scon; 01507 rc = fsmNext(fsm, IOSM_LSETFCON); 01508 } else 01509 fsm->fcontext = NULL; 01510 if (fsm->fcontext == NULL) 01511 rpmlog(RPMLOG_DEBUG, 01512 D_("%s directory created with perms %04o, no context.\n"), 01513 fsm->path, (unsigned)(st->st_mode & 07777)); 01514 else { 01515 rpmlog(RPMLOG_DEBUG, 01516 D_("%s directory created with perms %04o, context %s.\n"), 01517 fsm->path, (unsigned)(st->st_mode & 07777), 01518 fsm->fcontext); 01519 fsm->fcontext = NULL; 01520 scon = _free(scon); 01521 } 01522 } 01523 *te = '/'; 01524 } 01525 if (rc) 01526 /*@innerbreak@*/ break; 01527 } 01528 if (rc) break; 01529 01530 /* Save last validated path. */ 01531 /*@-compdef@*/ /* FIX: ldn/path annotations ? */ 01532 if (fsm->ldnalloc < (dnlen + 1)) { 01533 fsm->ldnalloc = dnlen + 100; 01534 fsm->ldn = xrealloc(fsm->ldn, fsm->ldnalloc); 01535 } 01536 if (fsm->ldn != NULL) { /* XXX can't happen */ 01537 strcpy(fsm->ldn, fsm->path); 01538 fsm->ldnlen = dnlen; 01539 } 01540 /*@=compdef@*/ 01541 } 01542 dnli = dnlFreeIterator(dnli); 01543 /*@=observertrans =dependenttrans@*/ 01544 01545 fsm->path = path; 01546 st->st_mode = st_mode; /* XXX restore st->st_mode */ 01547 /*@-compdef@*/ /* FIX: ldn/path annotations ? */ 01548 return rc; 01549 /*@=compdef@*/ 01550 } 01551 01552 #ifdef NOTYET 01553 01558 static int fsmStat(/*@special@*/ /*@partial@*/ IOSM_t fsm) 01559 /*@globals fileSystem, internalState @*/ 01560 /*@modifies fsm, fileSystem, internalState @*/ 01561 { 01562 int rc = 0; 01563 01564 if (fsm->path != NULL) { 01565 int saveernno = errno; 01566 rc = fsmUNSAFE(fsm, (!(fsm->mapFlags & IOSM_FOLLOW_SYMLINKS) 01567 ? IOSM_LSTAT : IOSM_STAT)); 01568 if (rc == IOSMERR_ENOENT) { 01569 errno = saveerrno; 01570 rc = 0; 01571 fsm->exists = 0; 01572 } else if (rc == 0) { 01573 fsm->exists = 1; 01574 } 01575 } else { 01576 /* Skip %ghost files on build. */ 01577 fsm->exists = 0; 01578 } 01579 return rc; 01580 } 01581 #endif 01582 01583 #define IS_DEV_LOG(_x) \ 01584 ((_x) != NULL && strlen(_x) >= (sizeof("/dev/log")-1) && \ 01585 !strncmp((_x), "/dev/log", sizeof("/dev/log")-1) && \ 01586 ((_x)[sizeof("/dev/log")-1] == '\0' || \ 01587 (_x)[sizeof("/dev/log")-1] == ';')) 01588 01589 /*@-compmempass@*/ 01590 int fsmStage(IOSM_t fsm, iosmFileStage stage) 01591 { 01592 #ifdef NOTUSED 01593 iosmFileStage prevStage = fsm->stage; 01594 const char * const prev = iosmFileStageString(prevStage); 01595 #endif 01596 const char * const cur = iosmFileStageString(stage); 01597 struct stat * st = &fsm->sb; 01598 struct stat * ost = &fsm->osb; 01599 int saveerrno = errno; 01600 int rc = fsm->rc; 01601 int i; 01602 01603 #define _fafilter(_a) \ 01604 (!((_a) == FA_CREATE || (_a) == FA_ERASE || (_a) == FA_COPYIN || (_a) == FA_COPYOUT) \ 01605 ? iosmFileActionString(_a) : "") 01606 01607 if (stage & IOSM_DEAD) { 01608 /* do nothing */ 01609 } else if (stage & IOSM_INTERNAL) { 01610 if (fsm->debug && !(stage & IOSM_SYSCALL)) 01611 rpmlog(RPMLOG_DEBUG, " %8s %06o%3d (%4d,%4d)%12lu %s %s\n", 01612 cur, 01613 (unsigned)st->st_mode, (int)st->st_nlink, 01614 (int)st->st_uid, (int)st->st_gid, (unsigned long)st->st_size, 01615 (fsm->path ? fsm->path : ""), 01616 _fafilter(fsm->action)); 01617 } else { 01618 const char * apath = NULL; 01619 if (fsm->path) 01620 (void) urlPath(fsm->path, &apath); 01621 fsm->stage = stage; 01622 if (fsm->debug || !(stage & IOSM_VERBOSE)) 01623 rpmlog(RPMLOG_DEBUG, "%-8s %06o%3d (%4d,%4d)%12lu %s %s\n", 01624 cur, 01625 (unsigned)st->st_mode, (int)st->st_nlink, 01626 (int)st->st_uid, (int)st->st_gid, (unsigned long)st->st_size, 01627 (apath ? apath + fsm->astriplen : ""), 01628 _fafilter(fsm->action)); 01629 } 01630 #undef _fafilter 01631 01632 switch (stage) { 01633 case IOSM_UNKNOWN: 01634 break; 01635 case IOSM_PKGINSTALL: 01636 while (1) { 01637 /* Clean fsm, free'ing memory. Read next archive header. */ 01638 rc = fsmUNSAFE(fsm, IOSM_INIT); 01639 01640 /* Exit on end-of-payload. */ 01641 if (rc == IOSMERR_HDR_TRAILER) { 01642 rc = 0; 01643 /*@loopbreak@*/ break; 01644 } 01645 01646 /* Exit on error. */ 01647 if (rc) { 01648 fsm->postpone = 1; 01649 (void) fsmNext(fsm, IOSM_UNDO); 01650 /*@loopbreak@*/ break; 01651 } 01652 01653 /* Extract file from archive. */ 01654 rc = fsmNext(fsm, IOSM_PROCESS); 01655 if (rc) { 01656 (void) fsmNext(fsm, IOSM_UNDO); 01657 /*@loopbreak@*/ break; 01658 } 01659 01660 /* Notify on success. */ 01661 (void) fsmNext(fsm, IOSM_NOTIFY); 01662 01663 rc = fsmNext(fsm, IOSM_FINI); 01664 if (rc) { 01665 /*@loopbreak@*/ break; 01666 } 01667 } 01668 break; 01669 case IOSM_PKGERASE: 01670 case IOSM_PKGCOMMIT: 01671 while (1) { 01672 /* Clean fsm, free'ing memory. */ 01673 rc = fsmUNSAFE(fsm, IOSM_INIT); 01674 01675 /* Exit on end-of-payload. */ 01676 if (rc == IOSMERR_HDR_TRAILER) { 01677 rc = 0; 01678 /*@loopbreak@*/ break; 01679 } 01680 01681 /* Rename/erase next item. */ 01682 if (fsmNext(fsm, IOSM_FINI)) 01683 /*@loopbreak@*/ break; 01684 } 01685 break; 01686 case IOSM_PKGBUILD: 01687 while (1) { 01688 01689 rc = fsmUNSAFE(fsm, IOSM_INIT); 01690 01691 /* Exit on end-of-payload. */ 01692 if (rc == IOSMERR_HDR_TRAILER) { 01693 rc = 0; 01694 /*@loopbreak@*/ break; 01695 } 01696 01697 /* Exit on error. */ 01698 if (rc) { 01699 fsm->postpone = 1; 01700 (void) fsmNext(fsm, IOSM_UNDO); 01701 /*@loopbreak@*/ break; 01702 } 01703 01704 /* Copy file into archive. */ 01705 rc = fsmNext(fsm, IOSM_PROCESS); 01706 if (rc) { 01707 (void) fsmNext(fsm, IOSM_UNDO); 01708 /*@loopbreak@*/ break; 01709 } 01710 01711 /* Notify on success. */ 01712 (void) fsmNext(fsm, IOSM_NOTIFY); 01713 01714 if (fsmNext(fsm, IOSM_FINI)) 01715 /*@loopbreak@*/ break; 01716 } 01717 01718 /* Flush partial sets of hard linked files. */ 01719 if (!(fsm->mapFlags & IOSM_ALL_HARDLINKS)) { 01720 int nlink, j; 01721 while ((fsm->li = fsm->links) != NULL) { 01722 fsm->links = fsm->li->next; 01723 fsm->li->next = NULL; 01724 01725 /* Re-calculate link count for archive header. */ 01726 for (j = -1, nlink = 0, i = 0; i < fsm->li->nlink; i++) { 01727 if (fsm->li->filex[i] < 0) 01728 /*@innercontinue@*/ continue; 01729 nlink++; 01730 if (j == -1) j = i; 01731 } 01732 /* XXX force the contents out as well. */ 01733 if (j != 0) { 01734 fsm->li->filex[0] = fsm->li->filex[j]; 01735 fsm->li->filex[j] = -1; 01736 } 01737 fsm->li->sb.st_nlink = nlink; 01738 01739 fsm->sb = fsm->li->sb; /* structure assignment */ 01740 fsm->osb = fsm->sb; /* structure assignment */ 01741 01742 if (!rc) rc = writeLinkedFile(fsm); 01743 01744 fsm->li = freeHardLink(fsm->li); 01745 } 01746 } 01747 01748 if (!rc) 01749 rc = fsmNext(fsm, IOSM_TRAILER); 01750 01751 break; 01752 case IOSM_CREATE: 01753 fsm->path = _free(fsm->path); 01754 fsm->lpath = _free(fsm->lpath); 01755 fsm->opath = _free(fsm->opath); 01756 fsm->dnlx = _free(fsm->dnlx); 01757 01758 fsm->ldn = _free(fsm->ldn); 01759 fsm->ldnalloc = fsm->ldnlen = 0; 01760 01761 fsm->rdsize = fsm->wrsize = 0; 01762 fsm->rdbuf = fsm->rdb = _free(fsm->rdb); 01763 fsm->wrbuf = fsm->wrb = _free(fsm->wrb); 01764 if (fsm->goal == IOSM_PKGINSTALL || fsm->goal == IOSM_PKGBUILD) { 01765 fsm->rdsize = 16 * BUFSIZ; 01766 fsm->rdbuf = fsm->rdb = xmalloc(fsm->rdsize); 01767 fsm->wrsize = 16 * BUFSIZ; 01768 fsm->wrbuf = fsm->wrb = xmalloc(fsm->wrsize); 01769 } 01770 01771 fsm->mkdirsdone = 0; 01772 fsm->ix = -1; 01773 fsm->links = NULL; 01774 fsm->li = NULL; 01775 errno = 0; /* XXX get rid of EBADF */ 01776 01777 /* Detect and create directories not explicitly in package. */ 01778 if (fsm->goal == IOSM_PKGINSTALL) { 01779 /*@-compdef@*/ 01780 rc = fsmNext(fsm, IOSM_MKDIRS); 01781 /*@=compdef@*/ 01782 if (!rc) fsm->mkdirsdone = 1; 01783 } 01784 01785 break; 01786 case IOSM_INIT: 01787 fsm->path = _free(fsm->path); 01788 fsm->lpath = _free(fsm->lpath); 01789 fsm->postpone = 0; 01790 fsm->diskchecked = fsm->exists = 0; 01791 fsm->subdir = NULL; 01792 fsm->suffix = (fsm->sufbuf[0] != '\0' ? fsm->sufbuf : NULL); 01793 fsm->action = FA_UNKNOWN; 01794 fsm->osuffix = NULL; 01795 fsm->nsuffix = NULL; 01796 01797 if (fsm->goal == IOSM_PKGINSTALL) { 01798 /* Read next header from payload, checking for end-of-payload. */ 01799 rc = fsmUNSAFE(fsm, IOSM_NEXT); 01800 } 01801 if (rc) break; 01802 01803 /* Identify mapping index. */ 01804 fsm->ix = ((fsm->goal == IOSM_PKGINSTALL) 01805 ? mapFind(fsm->iter, fsm->path) : mapNextIterator(fsm->iter)); 01806 01807 if (!(fsmGetFi(fsm)->mapflags & IOSM_PAYLOAD_LIST)) { 01808 /* Detect end-of-loop and/or mapping error. */ 01809 if (!(fsmGetFi(fsm)->mapflags & IOSM_PAYLOAD_EXTRACT)) { 01810 if (fsm->ix < 0) { 01811 if (fsm->goal == IOSM_PKGINSTALL) { 01812 #if 0 01813 rpmlog(RPMLOG_WARNING, 01814 _("archive file %s was not found in header file list\n"), 01815 fsm->path); 01816 #endif 01817 if (fsm->failedFile && *fsm->failedFile == NULL) 01818 *fsm->failedFile = xstrdup(fsm->path); 01819 rc = IOSMERR_UNMAPPED_FILE; 01820 } else { 01821 rc = IOSMERR_HDR_TRAILER; 01822 } 01823 break; 01824 } 01825 } 01826 01827 /* On non-install, mode must be known so that dirs don't get suffix. */ 01828 if (fsm->goal != IOSM_PKGINSTALL) { 01829 rpmfi fi = fsmGetFi(fsm); 01830 st->st_mode = fi->fmodes[fsm->ix]; 01831 } 01832 } 01833 01834 /* Generate file path. */ 01835 rc = fsmNext(fsm, IOSM_MAP); 01836 if (rc) break; 01837 01838 /* Perform lstat/stat for disk file. */ 01839 #ifdef NOTYET 01840 rc = fsmStat(fsm); 01841 #else 01842 if (fsm->path != NULL && 01843 !(fsm->goal == IOSM_PKGINSTALL && S_ISREG(st->st_mode))) 01844 { 01845 rc = fsmUNSAFE(fsm, (!(fsm->mapFlags & IOSM_FOLLOW_SYMLINKS) 01846 ? IOSM_LSTAT : IOSM_STAT)); 01847 if (rc == IOSMERR_ENOENT) { 01848 errno = saveerrno; 01849 rc = 0; 01850 fsm->exists = 0; 01851 } else if (rc == 0) { 01852 fsm->exists = 1; 01853 } 01854 } else { 01855 /* Skip %ghost files on build. */ 01856 fsm->exists = 0; 01857 } 01858 #endif 01859 fsm->diskchecked = 1; 01860 if (rc) break; 01861 01862 /* On non-install, the disk file stat is what's remapped. */ 01863 if (fsm->goal != IOSM_PKGINSTALL) 01864 *st = *ost; /* structure assignment */ 01865 01866 /* Remap file perms, owner, and group. */ 01867 rc = fsmMapAttrs(fsm); 01868 if (rc) break; 01869 01870 fsm->postpone = iosmFileActionSkipped(fsm->action); 01871 if (fsm->goal == IOSM_PKGINSTALL || fsm->goal == IOSM_PKGBUILD) { 01872 /*@-evalorder@*/ /* FIX: saveHardLink can modify fsm */ 01873 if (S_ISREG(st->st_mode) && st->st_nlink > 1) 01874 fsm->postpone = saveHardLink(fsm); 01875 /*@=evalorder@*/ 01876 } 01877 if (fsmGetFi(fsm)->mapflags & IOSM_PAYLOAD_LIST) fsm->postpone = 1; 01878 break; 01879 case IOSM_PRE: 01880 break; 01881 case IOSM_MAP: 01882 rc = fsmMapPath(fsm); 01883 break; 01884 case IOSM_MKDIRS: 01885 rc = fsmMkdirs(fsm); 01886 break; 01887 case IOSM_RMDIRS: 01888 if (fsm->dnlx) 01889 rc = fsmRmdirs(fsm); 01890 break; 01891 case IOSM_PROCESS: 01892 if (fsm->postpone) { 01893 if (fsm->goal == IOSM_PKGINSTALL) { 01894 /* XXX Skip over file body, archive headers already done. */ 01895 if (S_ISREG(st->st_mode)) 01896 rc = fsmNext(fsm, IOSM_EAT); 01897 } 01898 break; 01899 } 01900 01901 if (fsm->goal == IOSM_PKGBUILD) { 01902 if (fsm->fflags & RPMFILE_GHOST) /* XXX Don't if %ghost file. */ 01903 break; 01904 if (S_ISREG(st->st_mode) && st->st_nlink > 1) { 01905 struct hardLink_s * li, * prev; 01906 01907 if (!(fsm->mapFlags & IOSM_ALL_HARDLINKS)) break; 01908 rc = writeLinkedFile(fsm); 01909 if (rc) break; /* W2DO? */ 01910 01911 for (li = fsm->links, prev = NULL; li; prev = li, li = li->next) 01912 if (li == fsm->li) 01913 /*@loopbreak@*/ break; 01914 01915 if (prev == NULL) 01916 fsm->links = fsm->li->next; 01917 else 01918 prev->next = fsm->li->next; 01919 fsm->li->next = NULL; 01920 fsm->li = freeHardLink(fsm->li); 01921 } else { 01922 rc = writeFile(fsm, 1); 01923 } 01924 break; 01925 } 01926 01927 if (fsm->goal != IOSM_PKGINSTALL) 01928 break; 01929 01930 if (S_ISREG(st->st_mode) && fsm->lpath != NULL) { 01931 const char * opath = fsm->opath; 01932 char * t = xmalloc(strlen(fsm->lpath+1) + strlen(fsm->suffix) + 1); 01933 (void) stpcpy(t, fsm->lpath+1); 01934 fsm->opath = t; 01935 /* XXX link(fsm->opath, fsm->path) */ 01936 rc = fsmNext(fsm, IOSM_LINK); 01937 if (fsm->failedFile && rc != 0 && *fsm->failedFile == NULL) { 01938 *fsm->failedFile = xstrdup(fsm->path); 01939 } 01940 fsm->opath = _free(fsm->opath); 01941 fsm->opath = opath; 01942 break; /* XXX so that delayed hard links get skipped. */ 01943 } 01944 if (S_ISREG(st->st_mode)) { 01945 const char * path = fsm->path; 01946 if (fsm->osuffix) 01947 fsm->path = fsmFsPath(fsm, st, NULL, NULL); 01948 rc = fsmUNSAFE(fsm, IOSM_VERIFY); 01949 01950 if (rc == 0 && fsm->osuffix) { 01951 const char * opath = fsm->opath; 01952 fsm->opath = fsm->path; 01953 fsm->path = fsmFsPath(fsm, st, NULL, fsm->osuffix); 01954 rc = fsmNext(fsm, IOSM_RENAME); 01955 if (!rc) 01956 rpmlog(RPMLOG_WARNING, 01957 _("%s saved as %s\n"), 01958 (fsm->opath ? fsm->opath : ""), 01959 (fsm->path ? fsm->path : "")); 01960 fsm->path = _free(fsm->path); 01961 fsm->opath = opath; 01962 } 01963 01964 /*@-dependenttrans@*/ 01965 fsm->path = path; 01966 /*@=dependenttrans@*/ 01967 if (!(rc == IOSMERR_ENOENT)) return rc; 01968 rc = extractRegular(fsm); 01969 } else if (S_ISDIR(st->st_mode)) { 01970 mode_t st_mode = st->st_mode; 01971 rc = fsmUNSAFE(fsm, IOSM_VERIFY); 01972 if (rc == IOSMERR_ENOENT) { 01973 st->st_mode &= ~07777; /* XXX abuse st->st_mode */ 01974 st->st_mode |= 00700; 01975 rc = fsmNext(fsm, IOSM_MKDIR); 01976 st->st_mode = st_mode; /* XXX restore st->st_mode */ 01977 } 01978 } else if (S_ISLNK(st->st_mode)) { 01979 assert(fsm->lpath != NULL); 01980 /*@=dependenttrans@*/ 01981 rc = fsmUNSAFE(fsm, IOSM_VERIFY); 01982 if (rc == IOSMERR_ENOENT) 01983 rc = fsmNext(fsm, IOSM_SYMLINK); 01984 } else if (S_ISFIFO(st->st_mode)) { 01985 mode_t st_mode = st->st_mode; 01986 /* This mimics cpio S_ISSOCK() behavior but probably isnt' right */ 01987 rc = fsmUNSAFE(fsm, IOSM_VERIFY); 01988 if (rc == IOSMERR_ENOENT) { 01989 st->st_mode = 0000; /* XXX abuse st->st_mode */ 01990 rc = fsmNext(fsm, IOSM_MKFIFO); 01991 st->st_mode = st_mode; /* XXX restore st->st_mode */ 01992 } 01993 } else if (S_ISCHR(st->st_mode) || 01994 S_ISBLK(st->st_mode) || 01995 /*@-unrecog@*/ S_ISSOCK(st->st_mode) /*@=unrecog@*/) 01996 { 01997 rc = fsmUNSAFE(fsm, IOSM_VERIFY); 01998 if (rc == IOSMERR_ENOENT) 01999 rc = fsmNext(fsm, IOSM_MKNOD); 02000 } else { 02001 /* XXX Repackaged payloads may be missing files. */ 02002 if (fsm->repackaged) 02003 break; 02004 02005 /* XXX Special case /dev/log, which shouldn't be packaged anyways */ 02006 if (!IS_DEV_LOG(fsm->path)) 02007 rc = IOSMERR_UNKNOWN_FILETYPE; 02008 } 02009 if (S_ISREG(st->st_mode) && st->st_nlink > 1) { 02010 fsm->li->createdPath = fsm->li->linkIndex; 02011 rc = fsmMakeLinks(fsm); 02012 } 02013 break; 02014 case IOSM_POST: 02015 break; 02016 case IOSM_MKLINKS: 02017 rc = fsmMakeLinks(fsm); 02018 break; 02019 case IOSM_NOTIFY: /* XXX move from fsm to psm -> tsm */ 02020 if (fsm->goal == IOSM_PKGINSTALL || fsm->goal == IOSM_PKGBUILD) { 02021 rpmts ts = fsmGetTs(fsm); 02022 rpmfi fi = fsmGetFi(fsm); 02023 void * ptr; 02024 rpmuint64_t archivePos = fdGetCpioPos(fsm->cfd); 02025 if (archivePos > fi->archivePos) { 02026 fi->archivePos = (unsigned long long) archivePos; 02027 ptr = rpmtsNotify(ts, fi->te, RPMCALLBACK_INST_PROGRESS, 02028 fi->archivePos, fi->archiveSize); 02029 } 02030 } 02031 break; 02032 case IOSM_UNDO: 02033 if (fsm->postpone) 02034 break; 02035 if (fsm->goal == IOSM_PKGINSTALL) { 02036 /* XXX only erase if temp fn w suffix is in use */ 02037 if (fsm->sufbuf[0] != '\0') 02038 (void) fsmNext(fsm, 02039 (S_ISDIR(st->st_mode) ? IOSM_RMDIR : IOSM_UNLINK)); 02040 02041 #ifdef NOTYET /* XXX remove only dirs just created, not all. */ 02042 if (fsm->dnlx) 02043 (void) fsmNext(fsm, IOSM_RMDIRS); 02044 #endif 02045 errno = saveerrno; 02046 } 02047 if (fsm->failedFile && *fsm->failedFile == NULL) 02048 *fsm->failedFile = xstrdup(fsm->path); 02049 break; 02050 case IOSM_FINI: 02051 if (!fsm->postpone && fsm->commit) { 02052 if (fsm->goal == IOSM_PKGINSTALL) 02053 rc = ((S_ISREG(st->st_mode) && st->st_nlink > 1) 02054 ? fsmCommitLinks(fsm) : fsmNext(fsm, IOSM_COMMIT)); 02055 if (fsm->goal == IOSM_PKGCOMMIT) 02056 rc = fsmNext(fsm, IOSM_COMMIT); 02057 if (fsm->goal == IOSM_PKGERASE) 02058 rc = fsmNext(fsm, IOSM_COMMIT); 02059 } 02060 fsm->path = _free(fsm->path); 02061 fsm->lpath = _free(fsm->lpath); 02062 fsm->opath = _free(fsm->opath); 02063 memset(st, 0, sizeof(*st)); 02064 memset(ost, 0, sizeof(*ost)); 02065 break; 02066 case IOSM_COMMIT: 02067 /* Rename pre-existing modified or unmanaged file. */ 02068 if (fsm->osuffix && fsm->diskchecked && 02069 (fsm->exists || (fsm->goal == IOSM_PKGINSTALL && S_ISREG(st->st_mode)))) 02070 { 02071 const char * opath = fsm->opath; 02072 const char * path = fsm->path; 02073 fsm->opath = fsmFsPath(fsm, st, NULL, NULL); 02074 fsm->path = fsmFsPath(fsm, st, NULL, fsm->osuffix); 02075 rc = fsmNext(fsm, IOSM_RENAME); 02076 if (!rc) { 02077 rpmlog(RPMLOG_WARNING, _("%s saved as %s\n"), 02078 (fsm->opath ? fsm->opath : ""), 02079 (fsm->path ? fsm->path : "")); 02080 } 02081 fsm->path = _free(fsm->path); 02082 fsm->path = path; 02083 fsm->opath = _free(fsm->opath); 02084 fsm->opath = opath; 02085 } 02086 02087 /* Remove erased files. */ 02088 if (fsm->goal == IOSM_PKGERASE) { 02089 if (fsm->action == FA_ERASE) { 02090 rpmfi fi = fsmGetFi(fsm); 02091 if (S_ISDIR(st->st_mode)) { 02092 rc = fsmNext(fsm, IOSM_RMDIR); 02093 if (!rc) break; 02094 switch (rc) { 02095 case IOSMERR_ENOENT: /* XXX rmdir("/") linux 2.2.x kernel hack */ 02096 case IOSMERR_ENOTEMPTY: 02097 /* XXX make sure that build side permits %missingok on directories. */ 02098 if (fsm->fflags & RPMFILE_MISSINGOK) 02099 /*@innerbreak@*/ break; 02100 02101 /* XXX common error message. */ 02102 rpmlog( 02103 (fsm->strict_erasures ? RPMLOG_ERR : RPMLOG_DEBUG), 02104 _("%s rmdir of %s failed: Directory not empty\n"), 02105 rpmfiTypeString(fi), fsm->path); 02106 /*@innerbreak@*/ break; 02107 default: 02108 rpmlog( 02109 (fsm->strict_erasures ? RPMLOG_ERR : RPMLOG_DEBUG), 02110 _("%s rmdir of %s failed: %s\n"), 02111 rpmfiTypeString(fi), fsm->path, strerror(errno)); 02112 /*@innerbreak@*/ break; 02113 } 02114 } else { 02115 rc = fsmNext(fsm, IOSM_UNLINK); 02116 if (!rc) break; 02117 switch (rc) { 02118 case IOSMERR_ENOENT: 02119 if (fsm->fflags & RPMFILE_MISSINGOK) 02120 /*@innerbreak@*/ break; 02121 /*@fallthrough@*/ 02122 default: 02123 rpmlog( 02124 (fsm->strict_erasures ? RPMLOG_ERR : RPMLOG_DEBUG), 02125 _(" %s: unlink of %s failed: %s\n"), 02126 rpmfiTypeString(fi), fsm->path, strerror(errno)); 02127 /*@innerbreak@*/ break; 02128 } 02129 } 02130 } 02131 /* XXX Failure to remove is not (yet) cause for failure. */ 02132 if (!fsm->strict_erasures) rc = 0; 02133 break; 02134 } 02135 02136 /* XXX Special case /dev/log, which shouldn't be packaged anyways */ 02137 if (!(fsmGetFi(fsm)->mapflags & IOSM_PAYLOAD_EXTRACT)) { 02138 if (!S_ISSOCK(st->st_mode) && !IS_DEV_LOG(fsm->path)) { 02139 /* Rename temporary to final file name. */ 02140 if (!S_ISDIR(st->st_mode) && 02141 (fsm->subdir || fsm->suffix || fsm->nsuffix)) 02142 { 02143 fsm->opath = fsm->path; 02144 fsm->path = fsmFsPath(fsm, st, NULL, fsm->nsuffix); 02145 rc = fsmNext(fsm, IOSM_RENAME); 02146 if (rc) 02147 (void) Unlink(fsm->opath); 02148 else if (fsm->nsuffix) { 02149 const char * opath = fsmFsPath(fsm, st, NULL, NULL); 02150 rpmlog(RPMLOG_WARNING, _("%s created as %s\n"), 02151 (opath ? opath : ""), 02152 (fsm->path ? fsm->path : "")); 02153 opath = _free(opath); 02154 } 02155 fsm->opath = _free(fsm->opath); 02156 } 02157 /* 02158 * Set file security context (if not disabled). 02159 */ 02160 if (!rc && !getuid()) { 02161 rc = fsmMapFContext(fsm); 02162 if (!rc) 02163 rc = fsmNext(fsm, IOSM_LSETFCON); 02164 fsm->fcontext = NULL; 02165 } 02166 if (S_ISLNK(st->st_mode)) { 02167 if (!rc && !getuid()) 02168 rc = fsmNext(fsm, IOSM_LCHOWN); 02169 } else { 02170 if (!rc && !getuid()) 02171 rc = fsmNext(fsm, IOSM_CHOWN); 02172 if (!rc) 02173 rc = fsmNext(fsm, IOSM_CHMOD); 02174 if (!rc) { 02175 time_t mtime = st->st_mtime; 02176 rpmfi fi = fsmGetFi(fsm); 02177 if (fi->fmtimes) 02178 st->st_mtime = fi->fmtimes[fsm->ix]; 02179 rc = fsmNext(fsm, IOSM_UTIME); 02180 st->st_mtime = mtime; 02181 } 02182 } 02183 } 02184 } 02185 02186 /* Notify on success. */ 02187 if (!rc) rc = fsmNext(fsm, IOSM_NOTIFY); 02188 else if (fsm->failedFile && *fsm->failedFile == NULL) { 02189 *fsm->failedFile = fsm->path; 02190 fsm->path = NULL; 02191 } 02192 break; 02193 case IOSM_DESTROY: 02194 fsm->path = _free(fsm->path); 02195 02196 /* Check for hard links missing from payload. */ 02197 while ((fsm->li = fsm->links) != NULL) { 02198 fsm->links = fsm->li->next; 02199 fsm->li->next = NULL; 02200 if (fsm->goal == IOSM_PKGINSTALL && 02201 fsm->commit && fsm->li->linksLeft) 02202 { 02203 for (i = 0 ; i < fsm->li->linksLeft; i++) { 02204 if (fsm->li->filex[i] < 0) 02205 /*@innercontinue@*/ continue; 02206 rc = IOSMERR_MISSING_HARDLINK; 02207 if (fsm->failedFile && *fsm->failedFile == NULL) { 02208 fsm->ix = fsm->li->filex[i]; 02209 if (!fsmNext(fsm, IOSM_MAP)) { 02210 *fsm->failedFile = fsm->path; 02211 fsm->path = NULL; 02212 } 02213 } 02214 /*@loopbreak@*/ break; 02215 } 02216 } 02217 if (fsm->goal == IOSM_PKGBUILD && 02218 (fsm->mapFlags & IOSM_ALL_HARDLINKS)) 02219 { 02220 rc = IOSMERR_MISSING_HARDLINK; 02221 } 02222 fsm->li = freeHardLink(fsm->li); 02223 } 02224 fsm->ldn = _free(fsm->ldn); 02225 fsm->ldnalloc = fsm->ldnlen = 0; 02226 fsm->rdbuf = fsm->rdb = _free(fsm->rdb); 02227 fsm->wrbuf = fsm->wrb = _free(fsm->wrb); 02228 break; 02229 case IOSM_VERIFY: 02230 if (fsm->diskchecked && !fsm->exists) { 02231 rc = IOSMERR_ENOENT; 02232 break; 02233 } 02234 if (S_ISREG(st->st_mode)) { 02235 char * path = alloca(strlen(fsm->path) + sizeof("-RPMDELETE")); 02236 (void) stpcpy( stpcpy(path, fsm->path), "-RPMDELETE"); 02237 /* 02238 * XXX HP-UX (and other os'es) don't permit unlink on busy 02239 * XXX files. 02240 */ 02241 fsm->opath = fsm->path; 02242 fsm->path = path; 02243 rc = fsmNext(fsm, IOSM_RENAME); 02244 if (!rc) 02245 (void) fsmNext(fsm, IOSM_UNLINK); 02246 else 02247 rc = IOSMERR_UNLINK_FAILED; 02248 fsm->path = fsm->opath; 02249 fsm->opath = NULL; 02250 return (rc ? rc : IOSMERR_ENOENT); /* XXX HACK */ 02251 /*@notreached@*/ break; 02252 } else if (S_ISDIR(st->st_mode)) { 02253 if (S_ISDIR(ost->st_mode)) return 0; 02254 if (S_ISLNK(ost->st_mode)) { 02255 rc = fsmUNSAFE(fsm, IOSM_STAT); 02256 if (rc == IOSMERR_ENOENT) rc = 0; 02257 if (rc) break; 02258 errno = saveerrno; 02259 if (S_ISDIR(ost->st_mode)) return 0; 02260 } 02261 } else if (S_ISLNK(st->st_mode)) { 02262 if (S_ISLNK(ost->st_mode)) { 02263 /* XXX NUL terminated result in fsm->rdbuf, len in fsm->rdnb. */ 02264 rc = fsmUNSAFE(fsm, IOSM_READLINK); 02265 errno = saveerrno; 02266 if (rc) break; 02267 if (!strcmp(fsm->lpath, fsm->rdbuf)) return 0; 02268 } 02269 } else if (S_ISFIFO(st->st_mode)) { 02270 if (S_ISFIFO(ost->st_mode)) return 0; 02271 } else if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) { 02272 if ((S_ISCHR(ost->st_mode) || S_ISBLK(ost->st_mode)) && 02273 (ost->st_rdev == st->st_rdev)) return 0; 02274 } else if (S_ISSOCK(st->st_mode)) { 02275 if (S_ISSOCK(ost->st_mode)) return 0; 02276 } 02277 /* XXX shouldn't do this with commit/undo. */ 02278 rc = 0; 02279 if (fsm->stage == IOSM_PROCESS) rc = fsmNext(fsm, IOSM_UNLINK); 02280 if (rc == 0) rc = IOSMERR_ENOENT; 02281 return (rc ? rc : IOSMERR_ENOENT); /* XXX HACK */ 02282 /*@notreached@*/ break; 02283 02284 case IOSM_UNLINK: 02285 case IOSM_RENAME: 02286 case IOSM_MKDIR: 02287 case IOSM_RMDIR: 02288 case IOSM_LSETFCON: 02289 case IOSM_CHOWN: 02290 case IOSM_LCHOWN: 02291 case IOSM_CHMOD: 02292 case IOSM_UTIME: 02293 case IOSM_SYMLINK: 02294 case IOSM_LINK: 02295 case IOSM_MKFIFO: 02296 case IOSM_MKNOD: 02297 case IOSM_LSTAT: 02298 case IOSM_STAT: 02299 case IOSM_READLINK: 02300 case IOSM_CHROOT: 02301 rc = iosmStage(fsm, stage); 02302 break; 02303 02304 case IOSM_NEXT: 02305 case IOSM_EAT: 02306 case IOSM_POS: 02307 case IOSM_PAD: 02308 case IOSM_TRAILER: 02309 case IOSM_HREAD: 02310 case IOSM_HWRITE: 02311 case IOSM_DREAD: 02312 case IOSM_DWRITE: 02313 rc = iosmStage(fsm, stage); 02314 break; 02315 02316 case IOSM_ROPEN: 02317 case IOSM_READ: 02318 case IOSM_RCLOSE: 02319 rc = iosmStage(fsm, stage); 02320 break; 02321 case IOSM_WOPEN: 02322 case IOSM_WRITE: 02323 case IOSM_WCLOSE: 02324 rc = iosmStage(fsm, stage); 02325 break; 02326 02327 default: 02328 break; 02329 } 02330 02331 if (!(stage & IOSM_INTERNAL)) { 02332 fsm->rc = (rc == IOSMERR_HDR_TRAILER ? 0 : rc); 02333 } 02334 return rc; 02335 } 02336 /*@=compmempass@*/