00001
00005 #include "system.h"
00006
00007 #include <rpmlib.h>
00008 #include <rpmmacro.h>
00009 #include <rpmurl.h>
00010
00011 #include "cpio.h"
00012 #include "install.h"
00013 #include "depends.h"
00014 #include "misc.h"
00015 #include "debug.h"
00016
00017
00018
00022 struct callbackInfo {
00023 unsigned long archiveSize;
00024 rpmCallbackFunction notify;
00025 const char ** specFilePtr;
00026 Header h;
00027 rpmCallbackData notifyData;
00028 const void * pkgKey;
00029 };
00030
00034 struct fileMemory {
00035 const char ** names;
00036 const char ** cpioNames;
00037 const char ** md5sums;
00038 struct fileInfo * files;
00039 };
00040
00041 struct fileInfo {
00042 const char * cpioPath;
00043 const char * relativePath;
00044 const char * md5sum;
00045 uid_t uid;
00046 gid_t gid;
00047 uint_32 flags;
00048 uint_32 size;
00049 mode_t mode;
00050 char state;
00051 enum fileActions action;
00052 int install;
00053 } ;
00054
00055
00059 static struct tagMacro {
00060 const char * macroname;
00061 int tag;
00062 } tagMacros[] = {
00063 { "name", RPMTAG_NAME },
00064 { "version", RPMTAG_VERSION },
00065 { "release", RPMTAG_RELEASE },
00066 #if 0
00067 { "epoch", RPMTAG_EPOCH },
00068 #endif
00069 { NULL, 0 }
00070 };
00071
00077 static int rpmInstallLoadMacros(Header h)
00078 {
00079 struct tagMacro *tagm;
00080 union {
00081 const char * ptr;
00082 int_32 i32;
00083 } body;
00084 char numbuf[32];
00085 int type;
00086
00087 for (tagm = tagMacros; tagm->macroname != NULL; tagm++) {
00088 if (!headerGetEntry(h, tagm->tag, &type, (void **) &body, NULL))
00089 continue;
00090 switch (type) {
00091 case RPM_INT32_TYPE:
00092 sprintf(numbuf, "%d", body.i32);
00093 addMacro(NULL, tagm->macroname, NULL, numbuf, -1);
00094 break;
00095 case RPM_STRING_TYPE:
00096 addMacro(NULL, tagm->macroname, NULL, body.ptr, -1);
00097 break;
00098 }
00099 }
00100 return 0;
00101 }
00102
00107 static struct fileMemory *newFileMemory(void)
00108 {
00109 struct fileMemory *fileMem = xmalloc(sizeof(*fileMem));
00110 fileMem->files = NULL;
00111 fileMem->names = NULL;
00112 fileMem->cpioNames = NULL;
00113 fileMem->md5sums = NULL;
00114 return fileMem;
00115 }
00116
00121 static void freeFileMemory( struct fileMemory *fileMem)
00122 {
00123 if (fileMem->files) free(fileMem->files);
00124 if (fileMem->names) free(fileMem->names);
00125 if (fileMem->cpioNames) free(fileMem->cpioNames);
00126 if (fileMem->md5sums) free(fileMem->md5sums);
00127 free(fileMem);
00128 }
00129
00130
00141 static int assembleFileList(Header h, struct fileMemory ** memPtr,
00142 int * fileCountPtr, struct fileInfo ** filesPtr,
00143 int stripPrefixLength, enum fileActions * actions)
00144 {
00145 uint_32 * fileFlags;
00146 uint_32 * fileSizes;
00147 uint_16 * fileModes;
00148 struct fileMemory *mem = newFileMemory();
00149 struct fileInfo * files;
00150 struct fileInfo * file;
00151 int fileCount;
00152 int i;
00153
00154 *memPtr = mem;
00155
00156 if (!headerIsEntry(h, RPMTAG_BASENAMES)) return 0;
00157
00158 rpmBuildFileList(h, &mem->names, fileCountPtr);
00159
00160 if (headerIsEntry(h, RPMTAG_ORIGBASENAMES)) {
00161 buildOrigFileList(h, &mem->cpioNames, fileCountPtr);
00162 } else {
00163 rpmBuildFileList(h, &mem->cpioNames, fileCountPtr);
00164 }
00165
00166 fileCount = *fileCountPtr;
00167
00168 files = *filesPtr = mem->files = xcalloc(fileCount, sizeof(*mem->files));
00169
00170 headerGetEntry(h, RPMTAG_FILEMD5S, NULL, (void **) &mem->md5sums, NULL);
00171 headerGetEntry(h, RPMTAG_FILEFLAGS, NULL, (void **) &fileFlags, NULL);
00172 headerGetEntry(h, RPMTAG_FILEMODES, NULL, (void **) &fileModes, NULL);
00173 headerGetEntry(h, RPMTAG_FILESIZES, NULL, (void **) &fileSizes, NULL);
00174
00175 for (i = 0, file = files; i < fileCount; i++, file++) {
00176 file->state = RPMFILE_STATE_NORMAL;
00177 if (actions)
00178 file->action = actions[i];
00179 else
00180 file->action = FA_UNKNOWN;
00181 file->install = 1;
00182
00183 file->relativePath = mem->names[i];
00184 file->cpioPath = mem->cpioNames[i] + stripPrefixLength;
00185 file->md5sum = mem->md5sums[i];
00186 file->mode = fileModes[i];
00187 file->size = fileSizes[i];
00188 file->flags = fileFlags[i];
00189
00190 rpmMessage(RPMMESS_DEBUG, _(" file: %s action: %s\n"),
00191 file->relativePath, fileActionString(file->action));
00192 }
00193
00194 return 0;
00195 }
00196
00203 static void setFileOwners(Header h, struct fileInfo * files, int fileCount)
00204 {
00205 char ** fileOwners;
00206 char ** fileGroups;
00207 int i;
00208
00209 headerGetEntry(h, RPMTAG_FILEUSERNAME, NULL, (void **) &fileOwners, NULL);
00210 headerGetEntry(h, RPMTAG_FILEGROUPNAME, NULL, (void **) &fileGroups, NULL);
00211
00212 for (i = 0; i < fileCount; i++) {
00213 if (unameToUid(fileOwners[i], &files[i].uid)) {
00214 rpmMessage(RPMMESS_WARNING,
00215 _("user %s does not exist - using root\n"), fileOwners[i]);
00216 files[i].uid = 0;
00217
00218 files[i].mode &= ~S_ISUID;
00219 }
00220
00221 if (gnameToGid(fileGroups[i], &files[i].gid)) {
00222 rpmMessage(RPMMESS_WARNING,
00223 _("group %s does not exist - using root\n"), fileGroups[i]);
00224 files[i].gid = 0;
00225
00226 files[i].mode &= ~S_ISGID;
00227 }
00228 }
00229
00230 free(fileOwners);
00231 free(fileGroups);
00232 }
00233
00234 #ifdef DYING
00235
00240 static void trimChangelog(Header h)
00241 {
00242 int * times;
00243 char ** names, ** texts;
00244 long numToKeep = rpmExpandNumeric(
00245 "%{?_instchangelog:%{_instchagelog}}%{!?_instchangelog:5}");
00246 char * end;
00247 int count;
00248
00249 if (numToKeep < 0) return;
00250
00251 if (!numToKeep) {
00252 headerRemoveEntry(h, RPMTAG_CHANGELOGTIME);
00253 headerRemoveEntry(h, RPMTAG_CHANGELOGNAME);
00254 headerRemoveEntry(h, RPMTAG_CHANGELOGTEXT);
00255 return;
00256 }
00257
00258 if (!headerGetEntry(h, RPMTAG_CHANGELOGTIME, NULL, (void **) ×,
00259 &count) ||
00260 count < numToKeep) return;
00261 headerGetEntry(h, RPMTAG_CHANGELOGNAME, NULL, (void **) &names, &count);
00262 headerGetEntry(h, RPMTAG_CHANGELOGTEXT, NULL, (void **) &texts, &count);
00263
00264 headerModifyEntry(h, RPMTAG_CHANGELOGTIME, RPM_INT32_TYPE, times,
00265 numToKeep);
00266 headerModifyEntry(h, RPMTAG_CHANGELOGNAME, RPM_STRING_ARRAY_TYPE, names,
00267 numToKeep);
00268 headerModifyEntry(h, RPMTAG_CHANGELOGTEXT, RPM_STRING_ARRAY_TYPE, texts,
00269 numToKeep);
00270
00271 free(names);
00272 free(texts);
00273 }
00274 #endif
00275
00283 static int mergeFiles(Header h, Header newH, enum fileActions * actions)
00284 {
00285 int i, j, k, fileCount;
00286 int_32 type, count, dirNamesCount, dirCount;
00287 void * data, * newdata;
00288 int_32 * dirIndexes, * newDirIndexes;
00289 uint_32 * fileSizes, fileSize;
00290 char ** dirNames, ** newDirNames;
00291 static int_32 mergeTags[] = {
00292 RPMTAG_FILESIZES,
00293 RPMTAG_FILESTATES,
00294 RPMTAG_FILEMODES,
00295 RPMTAG_FILERDEVS,
00296 RPMTAG_FILEMTIMES,
00297 RPMTAG_FILEMD5S,
00298 RPMTAG_FILELINKTOS,
00299 RPMTAG_FILEFLAGS,
00300 RPMTAG_FILEUSERNAME,
00301 RPMTAG_FILEGROUPNAME,
00302 RPMTAG_FILEVERIFYFLAGS,
00303 RPMTAG_FILEDEVICES,
00304 RPMTAG_FILEINODES,
00305 RPMTAG_FILELANGS,
00306 RPMTAG_BASENAMES,
00307 0,
00308 };
00309 static int_32 requireTags[] = {
00310 RPMTAG_REQUIRENAME, RPMTAG_REQUIREVERSION, RPMTAG_REQUIREFLAGS,
00311 RPMTAG_PROVIDENAME, RPMTAG_PROVIDEVERSION, RPMTAG_PROVIDEFLAGS,
00312 RPMTAG_CONFLICTNAME, RPMTAG_CONFLICTVERSION, RPMTAG_CONFLICTFLAGS
00313 };
00314
00315 headerGetEntry(h, RPMTAG_SIZE, NULL, (void **) &fileSizes, NULL);
00316 fileSize = *fileSizes;
00317 headerGetEntry(newH, RPMTAG_FILESIZES, NULL, (void **) &fileSizes, &count);
00318 for (i = 0, fileCount = 0; i < count; i++)
00319 if (actions[i] != FA_SKIPMULTILIB) {
00320 fileCount++;
00321 fileSize += fileSizes[i];
00322 }
00323 headerModifyEntry(h, RPMTAG_SIZE, RPM_INT32_TYPE, &fileSize, 1);
00324 for (i = 0; mergeTags[i]; i++) {
00325 if (!headerGetEntryMinMemory(newH, mergeTags[i], &type,
00326 (const void **) &data, &count))
00327 continue;
00328 switch (type) {
00329 case RPM_CHAR_TYPE:
00330 case RPM_INT8_TYPE:
00331 newdata = xmalloc(fileCount * sizeof(int_8));
00332 for (j = 0, k = 0; j < count; j++)
00333 if (actions[j] != FA_SKIPMULTILIB)
00334 ((int_8 *) newdata)[k++] = ((int_8 *) data)[j];
00335 headerAddOrAppendEntry(h, mergeTags[i], type, newdata,
00336 fileCount);
00337 free (newdata);
00338 break;
00339 case RPM_INT16_TYPE:
00340 newdata = xmalloc(fileCount * sizeof(int_16));
00341 for (j = 0, k = 0; j < count; j++)
00342 if (actions[j] != FA_SKIPMULTILIB)
00343 ((int_16 *) newdata)[k++] = ((int_16 *) data)[j];
00344 headerAddOrAppendEntry(h, mergeTags[i], type, newdata, fileCount);
00345 free (newdata);
00346 break;
00347 case RPM_INT32_TYPE:
00348 newdata = xmalloc(fileCount * sizeof(int_32));
00349 for (j = 0, k = 0; j < count; j++)
00350 if (actions[j] != FA_SKIPMULTILIB)
00351 ((int_32 *) newdata)[k++] = ((int_32 *) data)[j];
00352 headerAddOrAppendEntry(h, mergeTags[i], type, newdata, fileCount);
00353 free (newdata);
00354 break;
00355 case RPM_STRING_ARRAY_TYPE:
00356 newdata = xmalloc(fileCount * sizeof(char *));
00357 for (j = 0, k = 0; j < count; j++)
00358 if (actions[j] != FA_SKIPMULTILIB)
00359 ((char **) newdata)[k++] = ((char **) data)[j];
00360 headerAddOrAppendEntry(h, mergeTags[i], type, newdata, fileCount);
00361 free (newdata);
00362 free (data);
00363 break;
00364 default:
00365 rpmError(RPMERR_DATATYPE, _("Data type %d not supported\n"),
00366 (int) type);
00367 return 1;
00368 break;
00369 }
00370 }
00371 headerGetEntry(newH, RPMTAG_DIRINDEXES, NULL, (void **) &newDirIndexes,
00372 &count);
00373 headerGetEntryMinMemory(newH, RPMTAG_DIRNAMES, NULL,
00374 (const void **) &newDirNames, NULL);
00375 headerGetEntry(h, RPMTAG_DIRINDEXES, NULL, (void **) &dirIndexes, NULL);
00376 headerGetEntryMinMemory(h, RPMTAG_DIRNAMES, NULL, (const void **) &data,
00377 &dirNamesCount);
00378
00379 dirNames = xcalloc(dirNamesCount + fileCount, sizeof(char *));
00380 for (i = 0; i < dirNamesCount; i++)
00381 dirNames[i] = ((char **) data)[i];
00382 dirCount = dirNamesCount;
00383 newdata = xmalloc(fileCount * sizeof(int_32));
00384 for (i = 0, k = 0; i < count; i++) {
00385 if (actions[i] == FA_SKIPMULTILIB)
00386 continue;
00387 for (j = 0; j < dirCount; j++)
00388 if (!strcmp(dirNames[j], newDirNames[newDirIndexes[i]]))
00389 break;
00390 if (j == dirCount)
00391 dirNames[dirCount++] = newDirNames[newDirIndexes[i]];
00392 ((int_32 *) newdata)[k++] = j;
00393 }
00394 headerAddOrAppendEntry(h, RPMTAG_DIRINDEXES, RPM_INT32_TYPE, newdata,
00395 fileCount);
00396 if (dirCount > dirNamesCount)
00397 headerAddOrAppendEntry(h, RPMTAG_DIRNAMES, RPM_STRING_ARRAY_TYPE,
00398 dirNames + dirNamesCount,
00399 dirCount - dirNamesCount);
00400 if (data) free (data);
00401 if (newDirNames) free (newDirNames);
00402 free (newdata);
00403 free (dirNames);
00404
00405 for (i = 0; i < 9; i += 3) {
00406 char **Names, **EVR, **newNames, **newEVR;
00407 uint_32 *Flags, *newFlags;
00408 int Count = 0, newCount = 0;
00409
00410 if (!headerGetEntryMinMemory(newH, requireTags[i], NULL,
00411 (const void **) &newNames, &newCount))
00412 continue;
00413
00414 headerGetEntryMinMemory(newH, requireTags[i+1], NULL,
00415 (const void **) &newEVR, NULL);
00416 headerGetEntry(newH, requireTags[i+2], NULL, (void **) &newFlags, NULL);
00417 if (headerGetEntryMinMemory(h, requireTags[i], NULL,
00418 (const void **) &Names, &Count))
00419 {
00420 headerGetEntryMinMemory(h, requireTags[i+1], NULL,
00421 (const void **) &EVR, NULL);
00422 headerGetEntry(h, requireTags[i+2], NULL, (void **) &Flags, NULL);
00423 for (j = 0; j < newCount; j++)
00424 for (k = 0; k < Count; k++)
00425 if (!strcmp (newNames[j], Names[k])
00426 && !strcmp (newEVR[j], EVR[k])
00427 && (newFlags[j] & RPMSENSE_SENSEMASK) ==
00428 (Flags[k] & RPMSENSE_SENSEMASK))
00429 {
00430 newNames[j] = NULL;
00431 break;
00432 }
00433 }
00434 for (j = 0, k = 0; j < newCount; j++) {
00435 if (!newNames[j] || !isDependsMULTILIB(newFlags[j]))
00436 continue;
00437 if (j != k) {
00438 newNames[k] = newNames[j];
00439 newEVR[k] = newEVR[j];
00440 newFlags[k] = newFlags[j];
00441 }
00442 k++;
00443 }
00444 if (k) {
00445 headerAddOrAppendEntry(h, requireTags[i],
00446 RPM_STRING_ARRAY_TYPE, newNames, k);
00447 headerAddOrAppendEntry(h, requireTags[i+1],
00448 RPM_STRING_ARRAY_TYPE, newEVR, k);
00449 headerAddOrAppendEntry(h, requireTags[i+2], RPM_INT32_TYPE,
00450 newFlags, k);
00451 }
00452 }
00453 return 0;
00454 }
00455
00462 static int markReplacedFiles(rpmdb rpmdb, const struct sharedFileInfo * replList)
00463 {
00464 const struct sharedFileInfo * fileInfo;
00465 rpmdbMatchIterator mi;
00466 Header h;
00467 unsigned int * offsets;
00468 unsigned int prev;
00469 int num;
00470
00471 num = prev = 0;
00472 for (fileInfo = replList; fileInfo->otherPkg; fileInfo++) {
00473 if (prev && prev == fileInfo->otherPkg)
00474 continue;
00475 prev = fileInfo->otherPkg;
00476 num++;
00477 }
00478 if (num == 0)
00479 return 0;
00480
00481 offsets = alloca(num * sizeof(*offsets));
00482 num = prev = 0;
00483 for (fileInfo = replList; fileInfo->otherPkg; fileInfo++) {
00484 if (prev && prev == fileInfo->otherPkg)
00485 continue;
00486 prev = fileInfo->otherPkg;
00487 offsets[num++] = fileInfo->otherPkg;
00488 }
00489
00490 mi = rpmdbInitIterator(rpmdb, RPMDBI_PACKAGES, NULL, 0);
00491 rpmdbAppendIterator(mi, offsets, num);
00492
00493 fileInfo = replList;
00494 while ((h = rpmdbNextIterator(mi)) != NULL) {
00495 char * secStates;
00496 int modified;
00497 int count;
00498
00499 modified = 0;
00500
00501 if (!headerGetEntry(h, RPMTAG_FILESTATES, NULL, (void **)&secStates, &count))
00502 continue;
00503
00504 prev = rpmdbGetIteratorOffset(mi);
00505 num = 0;
00506 while (fileInfo->otherPkg && fileInfo->otherPkg == prev) {
00507 assert(fileInfo->otherFileNum < count);
00508 if (secStates[fileInfo->otherFileNum] != RPMFILE_STATE_REPLACED) {
00509 secStates[fileInfo->otherFileNum] = RPMFILE_STATE_REPLACED;
00510 if (modified == 0) {
00511
00512 modified = 1;
00513 rpmdbSetIteratorModified(mi, modified);
00514 }
00515 num++;
00516 }
00517 fileInfo++;
00518 }
00519 }
00520 rpmdbFreeIterator(mi);
00521
00522 return 0;
00523 }
00524
00527 static void callback(struct cpioCallbackInfo * cpioInfo, void * data)
00528 {
00529 struct callbackInfo * ourInfo = data;
00530 const char * chptr;
00531
00532 if (ourInfo->notify)
00533 (void)ourInfo->notify(ourInfo->h, RPMCALLBACK_INST_PROGRESS,
00534 cpioInfo->bytesProcessed,
00535 ourInfo->archiveSize, ourInfo->pkgKey,
00536 ourInfo->notifyData);
00537
00538 if (ourInfo->specFilePtr) {
00539 chptr = cpioInfo->file + strlen(cpioInfo->file) - 5;
00540 if (!strcmp(chptr, ".spec"))
00541 *ourInfo->specFilePtr = xstrdup(cpioInfo->file);
00542 }
00543 }
00544
00561 static int installArchive(FD_t fd, struct fileInfo * files, int fileCount,
00562 rpmCallbackFunction notify, rpmCallbackData notifyData,
00563 const void * pkgKey, Header h,
00564 const char ** specFile, int archiveSize)
00565 {
00566 int rc, i;
00567 struct cpioFileMapping * map = NULL;
00568 int mappedFiles = 0;
00569 const char * failedFile = NULL;
00570 struct callbackInfo info;
00571 char * rpmio_flags;
00572 FD_t cfd;
00573 int urltype;
00574 int saveerrno;
00575
00576 if (!files) {
00577
00578 fileCount = 0;
00579 } else if (!fileCount) {
00580
00581 return 0;
00582 }
00583
00584 info.archiveSize = archiveSize;
00585 info.notify = notify;
00586 info.notifyData = notifyData;
00587 info.specFilePtr = specFile;
00588 info.h = headerLink(h);
00589 info.pkgKey = pkgKey;
00590
00591 if (specFile) *specFile = NULL;
00592
00593 if (files) {
00594 map = alloca(sizeof(*map) * fileCount);
00595 for (i = 0, mappedFiles = 0; i < fileCount; i++) {
00596 if (!files[i].install) continue;
00597
00598 map[mappedFiles].archivePath = files[i].cpioPath;
00599 #ifdef DYING
00600 map[mappedFiles].fsPath = files[i].relativePath;
00601 #else
00602 urltype = urlPath(files[i].relativePath, &map[mappedFiles].fsPath);
00603 #endif
00604
00605
00606 map[mappedFiles].md5sum = headerIsEntry(h, RPMTAG_SOURCERPM)
00607 ? files[i].md5sum : NULL;
00608 map[mappedFiles].finalMode = files[i].mode;
00609 map[mappedFiles].finalUid = files[i].uid;
00610 map[mappedFiles].finalGid = files[i].gid;
00611 map[mappedFiles].mapFlags = CPIO_MAP_PATH | CPIO_MAP_MODE |
00612 CPIO_MAP_UID | CPIO_MAP_GID;
00613 mappedFiles++;
00614 }
00615
00616 qsort(map, mappedFiles, sizeof(*map), cpioFileMapCmp);
00617 }
00618
00619 if (notify)
00620 (void)notify(h, RPMCALLBACK_INST_PROGRESS, 0, archiveSize, pkgKey,
00621 notifyData);
00622
00623
00624 { const char * payload_compressor = NULL;
00625 char * t;
00626
00627 if (!headerGetEntry(h, RPMTAG_PAYLOADCOMPRESSOR, NULL,
00628 (void **) &payload_compressor, NULL))
00629 payload_compressor = "gzip";
00630 rpmio_flags = t = alloca(sizeof("r.gzdio"));
00631 *t++ = 'r';
00632 if (!strcmp(payload_compressor, "gzip"))
00633 t = stpcpy(t, ".gzdio");
00634 if (!strcmp(payload_compressor, "bzip2"))
00635 t = stpcpy(t, ".bzdio");
00636 }
00637
00638 (void) Fflush(fd);
00639 cfd = Fdopen(fdDup(Fileno(fd)), rpmio_flags);
00640 rc = cpioInstallArchive(cfd, map, mappedFiles,
00641 ((notify && archiveSize) || specFile) ? callback : NULL,
00642 &info, &failedFile);
00643 saveerrno = errno;
00644 Fclose(cfd);
00645 headerFree(info.h);
00646
00647 if (rc) {
00648
00649
00650 errno = saveerrno;
00651 rpmError(RPMERR_CPIO, _("unpacking of archive failed%s%s: %s\n"),
00652 (failedFile != NULL ? _(" on file ") : ""),
00653 (failedFile != NULL ? failedFile : ""),
00654 cpioStrerror(rc));
00655 rc = 1;
00656 } else if (notify) {
00657 if (archiveSize)
00658 (void)notify(h, RPMCALLBACK_INST_PROGRESS, archiveSize, archiveSize,
00659 pkgKey, notifyData);
00660 else
00661 (void)notify(h, RPMCALLBACK_INST_PROGRESS, 100, 100,
00662 pkgKey, notifyData);
00663 rc = 0;
00664 }
00665
00666 if (failedFile)
00667 free((void *)failedFile);
00668
00669 return rc;
00670 }
00671
00681 static int installSources(Header h, const char * rootDir, FD_t fd,
00682 const char ** specFilePtr,
00683 rpmCallbackFunction notify, rpmCallbackData notifyData)
00684 {
00685 const char * specFile = NULL;
00686 int specFileIndex = -1;
00687 const char * realSourceDir = NULL;
00688 const char * realSpecDir = NULL;
00689 char * instSpecFile, * correctSpecFile;
00690 int fileCount = 0;
00691 uint_32 * archiveSizePtr = NULL;
00692 struct fileMemory *fileMem = NULL;
00693 struct fileInfo * files = NULL;
00694 int i;
00695 const char * currDir = NULL;
00696 uid_t currUid = getuid();
00697 gid_t currGid = getgid();
00698 struct stat st;
00699 int rc = 0;
00700
00701 rpmMessage(RPMMESS_DEBUG, _("installing a source package\n"));
00702
00703 realSourceDir = rpmGenPath(rootDir, "%{_sourcedir}", "");
00704 if ((rc = Stat(realSourceDir, &st)) < 0) {
00705 int ut = urlPath(realSourceDir, NULL);
00706 switch (ut) {
00707 case URL_IS_PATH:
00708 case URL_IS_UNKNOWN:
00709 if (errno != ENOENT)
00710 break;
00711
00712 case URL_IS_FTP:
00713 case URL_IS_HTTP:
00714
00715 rc = Mkdir(realSourceDir, 0755);
00716 break;
00717 case URL_IS_DASH:
00718 break;
00719 }
00720 if (rc < 0) {
00721 rpmError(RPMERR_CREATE, _("cannot create sourcedir %s\n"),
00722 realSourceDir);
00723 rc = 2;
00724 goto exit;
00725 }
00726 }
00727 if ((rc = Access(realSourceDir, W_OK))) {
00728 rpmError(RPMERR_CREATE, _("cannot write to %s\n"), realSourceDir);
00729 rc = 2;
00730 goto exit;
00731 }
00732 rpmMessage(RPMMESS_DEBUG, _("sources in: %s\n"), realSourceDir);
00733
00734 realSpecDir = rpmGenPath(rootDir, "%{_specdir}", "");
00735 if ((rc = Stat(realSpecDir, &st)) < 0) {
00736 int ut = urlPath(realSpecDir, NULL);
00737 switch (ut) {
00738 case URL_IS_PATH:
00739 case URL_IS_UNKNOWN:
00740 if (errno != ENOENT)
00741 break;
00742
00743 case URL_IS_FTP:
00744 case URL_IS_HTTP:
00745
00746 rc = Mkdir(realSpecDir, 0755);
00747 break;
00748 case URL_IS_DASH:
00749 break;
00750 }
00751 if (rc < 0) {
00752 rpmError(RPMERR_CREATE, _("cannot create specdir %s\n"),
00753 realSpecDir);
00754 rc = 2;
00755 goto exit;
00756 }
00757 }
00758 if ((rc = Access(realSpecDir, W_OK))) {
00759 rpmError(RPMERR_CREATE, _("cannot write to %s\n"), realSpecDir);
00760 rc = 2;
00761 goto exit;
00762 }
00763 rpmMessage(RPMMESS_DEBUG, _("spec file in: %s\n"), realSpecDir);
00764
00765 if (h != NULL && headerIsEntry(h, RPMTAG_BASENAMES)) {
00766
00767 assembleFileList(h, &fileMem, &fileCount, &files, 0, NULL);
00768
00769 for (i = 0; i < fileCount; i++) {
00770 files[i].relativePath = files[i].relativePath;
00771 files[i].uid = currUid;
00772 files[i].gid = currGid;
00773 }
00774
00775 if (headerIsEntry(h, RPMTAG_COOKIE))
00776 for (i = 0; i < fileCount; i++)
00777 if (files[i].flags & RPMFILE_SPECFILE) break;
00778
00779 if (i == fileCount) {
00780
00781 for (i = 0; i < fileCount; i++) {
00782 const char *chptr;
00783 chptr = files[i].cpioPath + strlen(files[i].cpioPath) - 5;
00784 if (!strcmp(chptr, ".spec")) break;
00785 }
00786 }
00787
00788 if (i < fileCount) {
00789 char *t = alloca(strlen(realSpecDir) +
00790 strlen(files[i].cpioPath) + 5);
00791 (void)stpcpy(stpcpy(stpcpy(t,realSpecDir), "/"), files[i].cpioPath);
00792 files[i].relativePath = t;
00793 specFileIndex = i;
00794 } else {
00795 rpmError(RPMERR_NOSPEC,
00796 _("source package contains no .spec file\n"));
00797 rc = 2;
00798 goto exit;
00799 }
00800 }
00801
00802 if (notify) {
00803 (void)notify(h, RPMCALLBACK_INST_START, 0, 0, NULL, notifyData);
00804 }
00805
00806 currDir = currentDirectory();
00807
00808 if (!headerGetEntry(h, RPMTAG_ARCHIVESIZE, NULL,
00809 (void **) &archiveSizePtr, NULL))
00810 archiveSizePtr = NULL;
00811
00812 Chdir(realSourceDir);
00813 if (installArchive(fd, fileCount > 0 ? files : NULL,
00814 fileCount, notify, notifyData, NULL, h,
00815 specFileIndex >= 0 ? NULL : &specFile,
00816 archiveSizePtr ? *archiveSizePtr : 0)) {
00817 rc = 2;
00818 goto exit;
00819 }
00820 Chdir(currDir);
00821
00822 if (specFileIndex == -1) {
00823 if (specFile == NULL) {
00824 rpmError(RPMERR_NOSPEC,
00825 _("source package contains no .spec file\n"));
00826 rc = 1;
00827 goto exit;
00828 }
00829
00830
00831
00832
00833 instSpecFile = alloca(strlen(realSourceDir) + strlen(specFile) + 2);
00834 (void)stpcpy(stpcpy(stpcpy(instSpecFile,realSourceDir), "/"), specFile);
00835
00836 correctSpecFile = alloca(strlen(realSpecDir) + strlen(specFile) + 2);
00837 (void)stpcpy(stpcpy(stpcpy(correctSpecFile,realSpecDir), "/"), specFile);
00838
00839 free((void *)specFile);
00840
00841 if (strcmp(instSpecFile, correctSpecFile)) {
00842 rpmMessage(RPMMESS_DEBUG,
00843 _("renaming %s to %s\n"), instSpecFile, correctSpecFile);
00844 if ((rc = Rename(instSpecFile, correctSpecFile))) {
00845 rpmError(RPMERR_RENAME, _("rename of %s to %s failed: %s\n"),
00846 instSpecFile, correctSpecFile, strerror(errno));
00847 rc = 2;
00848 goto exit;
00849 }
00850 }
00851
00852 if (specFilePtr)
00853 *specFilePtr = xstrdup(correctSpecFile);
00854 } else {
00855 if (specFilePtr)
00856 *specFilePtr = xstrdup(files[specFileIndex].relativePath);
00857 }
00858 rc = 0;
00859
00860 exit:
00861 if (fileMem) freeFileMemory(fileMem);
00862 if (currDir) free((void *)currDir);
00863 if (realSpecDir) free((void *)realSpecDir);
00864 if (realSourceDir) free((void *)realSourceDir);
00865 return rc;
00866 }
00867
00868 int rpmVersionCompare(Header first, Header second)
00869 {
00870 const char * one, * two;
00871 int_32 * epochOne, * epochTwo;
00872 int rc;
00873
00874 if (!headerGetEntry(first, RPMTAG_EPOCH, NULL, (void **) &epochOne, NULL))
00875 epochOne = NULL;
00876 if (!headerGetEntry(second, RPMTAG_EPOCH, NULL, (void **) &epochTwo,
00877 NULL))
00878 epochTwo = NULL;
00879
00880 if (epochOne && !epochTwo)
00881 return 1;
00882 else if (!epochOne && epochTwo)
00883 return -1;
00884 else if (epochOne && epochTwo) {
00885 if (*epochOne < *epochTwo)
00886 return -1;
00887 else if (*epochOne > *epochTwo)
00888 return 1;
00889 }
00890
00891 headerGetEntry(first, RPMTAG_VERSION, NULL, (void **) &one, NULL);
00892 headerGetEntry(second, RPMTAG_VERSION, NULL, (void **) &two, NULL);
00893
00894 rc = rpmvercmp(one, two);
00895 if (rc)
00896 return rc;
00897
00898 headerGetEntry(first, RPMTAG_RELEASE, NULL, (void **) &one, NULL);
00899 headerGetEntry(second, RPMTAG_RELEASE, NULL, (void **) &two, NULL);
00900
00901 return rpmvercmp(one, two);
00902 }
00903
00904 const char *const fileActionString(enum fileActions a)
00905 {
00906 switch (a) {
00907 case FA_UNKNOWN: return "unknown";
00908 case FA_CREATE: return "create";
00909 case FA_BACKUP: return "backup";
00910 case FA_SAVE: return "save";
00911 case FA_SKIP: return "skip";
00912 case FA_ALTNAME: return "altname";
00913 case FA_REMOVE: return "remove";
00914 case FA_SKIPNSTATE: return "skipnstate";
00915 case FA_SKIPNETSHARED: return "skipnetshared";
00916 case FA_SKIPMULTILIB: return "skipmultilib";
00917 }
00918
00919 return "???";
00920 }
00921
00922 int rpmInstallSourcePackage(const char * rootDir, FD_t fd,
00923 const char ** specFile,
00924 rpmCallbackFunction notify, rpmCallbackData notifyData,
00925 char ** cookie)
00926 {
00927 int rc, isSource;
00928 Header h;
00929 int major, minor;
00930
00931 rc = rpmReadPackageHeader(fd, &h, &isSource, &major, &minor);
00932 if (rc) return rc;
00933
00934 if (!isSource) {
00935 rpmError(RPMERR_NOTSRPM, _("source package expected, binary found\n"));
00936 return 2;
00937 }
00938
00939 if (cookie) {
00940 *cookie = NULL;
00941 if (h != NULL &&
00942 headerGetEntry(h, RPMTAG_COOKIE, NULL, (void **) cookie, NULL)) {
00943 *cookie = xstrdup(*cookie);
00944 }
00945 }
00946
00947 rpmInstallLoadMacros(h);
00948
00949 rc = installSources(h, rootDir, fd, specFile, notify, notifyData);
00950 if (h)
00951 headerFree(h);
00952
00953 return rc;
00954 }
00955
00956 int installBinaryPackage(const rpmTransactionSet ts, FD_t fd, Header h,
00957 const void * pkgKey, enum fileActions * actions,
00958 struct sharedFileInfo * sharedList)
00959 {
00960 rpmtransFlags transFlags = ts->transFlags;
00961 int rc;
00962 const char * name, * version, * release;
00963 int fileCount = 0;
00964 int type, count;
00965 struct fileInfo * files;
00966 int i;
00967 Header oldH = NULL;
00968 int otherOffset = 0;
00969 int scriptArg;
00970 int stripSize = 1;
00971 struct fileMemory *fileMem = NULL;
00972
00973
00974 if (transFlags & (RPMTRANS_FLAG_JUSTDB | RPMTRANS_FLAG_MULTILIB))
00975 transFlags |= RPMTRANS_FLAG_NOSCRIPTS;
00976
00977 headerNVR(h, &name, &version, &release);
00978
00979 rpmMessage(RPMMESS_DEBUG, _("package: %s-%s-%s files test = %d\n"),
00980 name, version, release, transFlags & RPMTRANS_FLAG_TEST);
00981
00982 if ((scriptArg = rpmdbCountPackages(ts->rpmdb, name)) < 0) {
00983 rc = 2;
00984 goto exit;
00985 }
00986 scriptArg += 1;
00987
00988 { rpmdbMatchIterator mi;
00989 mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_NAME, name, 0);
00990 rpmdbSetIteratorVersion(mi, version);
00991 rpmdbSetIteratorRelease(mi, release);
00992 while ((oldH = rpmdbNextIterator(mi))) {
00993 otherOffset = rpmdbGetIteratorOffset(mi);
00994 oldH = (transFlags & RPMTRANS_FLAG_MULTILIB)
00995 ? headerCopy(oldH) : NULL;
00996 break;
00997 }
00998 rpmdbFreeIterator(mi);
00999 }
01000
01001 if (!(transFlags & RPMTRANS_FLAG_JUSTDB) && headerIsEntry(h, RPMTAG_BASENAMES)) {
01002 const char * defaultPrefix;
01003
01004
01005
01006 if (headerGetEntry(h, RPMTAG_DEFAULTPREFIX, NULL, (void **)
01007 &defaultPrefix, NULL)) {
01008 stripSize = strlen(defaultPrefix) + 1;
01009 } else {
01010 stripSize = 1;
01011 }
01012
01013 if (assembleFileList(h, &fileMem, &fileCount, &files, stripSize,
01014 actions)) {
01015 rc = 2;
01016 goto exit;
01017 }
01018 } else {
01019 files = NULL;
01020 }
01021
01022 if (transFlags & RPMTRANS_FLAG_TEST) {
01023 rpmMessage(RPMMESS_DEBUG, _("stopping install as we're running --test\n"));
01024 rc = 0;
01025 goto exit;
01026 }
01027
01028 rpmMessage(RPMMESS_DEBUG, _("running preinstall script (if any)\n"));
01029
01030 rc = runInstScript(ts, h, RPMTAG_PREIN, RPMTAG_PREINPROG, scriptArg,
01031 transFlags & RPMTRANS_FLAG_NOSCRIPTS);
01032
01033 if (rc) {
01034 rc = 2;
01035 rpmError(RPMERR_SCRIPT,
01036 _("skipping %s-%s-%s install, %%pre scriptlet failed rc %d\n"),
01037 name, version, release, rc);
01038 goto exit;
01039 }
01040
01041 if (ts->rootDir) {
01042
01043
01044 (void)getpwnam("root");
01045 endpwent();
01046
01047 chdir("/");
01048 chroot(ts->rootDir);
01049 ts->chrootDone = 1;
01050 }
01051
01052 if (files) {
01053 setFileOwners(h, files, fileCount);
01054
01055 for (i = 0; i < fileCount; i++) {
01056 char * ext;
01057 char * newpath;
01058
01059 ext = NULL;
01060
01061 switch (files[i].action) {
01062 case FA_BACKUP:
01063 ext = ".rpmorig";
01064 break;
01065
01066 case FA_ALTNAME:
01067 newpath = alloca(strlen(files[i].relativePath) + 20);
01068 (void)stpcpy(stpcpy(newpath, files[i].relativePath), ".rpmnew");
01069 rpmMessage(RPMMESS_WARNING, _("%s created as %s\n"),
01070 files[i].relativePath, newpath);
01071 files[i].relativePath = newpath;
01072 break;
01073
01074 case FA_SAVE:
01075 ext = ".rpmsave";
01076 break;
01077
01078 case FA_CREATE:
01079 break;
01080
01081 case FA_SKIP:
01082 case FA_SKIPMULTILIB:
01083 files[i].install = 0;
01084 break;
01085
01086 case FA_SKIPNSTATE:
01087 files[i].state = RPMFILE_STATE_NOTINSTALLED;
01088 files[i].install = 0;
01089 break;
01090
01091 case FA_SKIPNETSHARED:
01092 files[i].state = RPMFILE_STATE_NETSHARED;
01093 files[i].install = 0;
01094 break;
01095
01096 case FA_UNKNOWN:
01097 case FA_REMOVE:
01098 files[i].install = 0;
01099 break;
01100 }
01101
01102 if (ext && access(files[i].relativePath, F_OK) == 0) {
01103 newpath = alloca(strlen(files[i].relativePath) + 20);
01104 (void)stpcpy(stpcpy(newpath, files[i].relativePath), ext);
01105 rpmMessage(RPMMESS_WARNING, _("%s saved as %s\n"),
01106 files[i].relativePath, newpath);
01107
01108 if (rename(files[i].relativePath, newpath)) {
01109 rpmError(RPMERR_RENAME, _("rename of %s to %s failed: %s\n"),
01110 files[i].relativePath, newpath, strerror(errno));
01111 rc = 2;
01112 goto exit;
01113 }
01114 }
01115 }
01116
01117 { uint_32 * archiveSizePtr;
01118
01119 if (!headerGetEntry(h, RPMTAG_ARCHIVESIZE, &type,
01120 (void **) &archiveSizePtr, &count))
01121 archiveSizePtr = NULL;
01122
01123 if (ts->notify) {
01124 (void)ts->notify(h, RPMCALLBACK_INST_START, 0, 0,
01125 pkgKey, ts->notifyData);
01126 }
01127
01128
01129 if (installArchive(fd, files, fileCount, ts->notify, ts->notifyData, pkgKey,
01130 h, NULL, archiveSizePtr ? *archiveSizePtr : 0)) {
01131 rc = 2;
01132 goto exit;
01133 }
01134 }
01135
01136 { char *fileStates = xmalloc(sizeof(*fileStates) * fileCount);
01137 for (i = 0; i < fileCount; i++)
01138 fileStates[i] = files[i].state;
01139
01140 headerAddEntry(h, RPMTAG_FILESTATES, RPM_CHAR_TYPE, fileStates,
01141 fileCount);
01142
01143 free(fileStates);
01144 }
01145 if (fileMem) freeFileMemory(fileMem);
01146 fileMem = NULL;
01147 } else if (transFlags & RPMTRANS_FLAG_JUSTDB) {
01148 if (headerGetEntry(h, RPMTAG_BASENAMES, NULL, NULL, &fileCount)) {
01149 char * fileStates = xmalloc(sizeof(*fileStates) * fileCount);
01150 memset(fileStates, RPMFILE_STATE_NORMAL, fileCount);
01151 headerAddEntry(h, RPMTAG_FILESTATES, RPM_CHAR_TYPE, fileStates,
01152 fileCount);
01153 free(fileStates);
01154 }
01155 }
01156
01157 { int_32 installTime = time(NULL);
01158 headerAddEntry(h, RPMTAG_INSTALLTIME, RPM_INT32_TYPE, &installTime, 1);
01159 }
01160
01161 if (ts->rootDir) {
01162 chroot(".");
01163 ts->chrootDone = 0;
01164 chdir(ts->currDir);
01165 }
01166
01167 #ifdef DYING
01168 trimChangelog(h);
01169 #endif
01170
01171
01172
01173 if (otherOffset)
01174 rpmdbRemove(ts->rpmdb, ts->id, otherOffset);
01175
01176 if (transFlags & RPMTRANS_FLAG_MULTILIB) {
01177 uint_32 multiLib, * newMultiLib, * p;
01178
01179 if (headerGetEntry(h, RPMTAG_MULTILIBS, NULL, (void **) &newMultiLib,
01180 NULL)
01181 && headerGetEntry(oldH, RPMTAG_MULTILIBS, NULL,
01182 (void **) &p, NULL)) {
01183 multiLib = *p;
01184 multiLib |= *newMultiLib;
01185 headerModifyEntry(oldH, RPMTAG_MULTILIBS, RPM_INT32_TYPE,
01186 &multiLib, 1);
01187 }
01188 if (mergeFiles(oldH, h, actions)) {
01189 rc = 2;
01190 goto exit;
01191 }
01192 }
01193
01194 if (rpmdbAdd(ts->rpmdb, ts->id, h)) {
01195 rc = 2;
01196 goto exit;
01197 }
01198
01199 rpmMessage(RPMMESS_DEBUG, _("running postinstall scripts (if any)\n"));
01200
01201 if (runInstScript(ts, h, RPMTAG_POSTIN, RPMTAG_POSTINPROG, scriptArg,
01202 (transFlags & RPMTRANS_FLAG_NOSCRIPTS))) {
01203 rc = 2;
01204 goto exit;
01205 }
01206
01207 if (!(transFlags & RPMTRANS_FLAG_NOTRIGGERS)) {
01208
01209 if (runTriggers(ts, RPMSENSE_TRIGGERIN, h, 0)) {
01210 rc = 2;
01211 goto exit;
01212 }
01213
01214
01215
01216
01217
01218 if (runImmedTriggers(ts, RPMSENSE_TRIGGERIN, h, 0)) {
01219 rc = 2;
01220 goto exit;
01221 }
01222 }
01223
01224 if (sharedList)
01225 markReplacedFiles(ts->rpmdb, sharedList);
01226
01227 rc = 0;
01228
01229 exit:
01230 if (ts->chrootDone) {
01231 chroot(".");
01232 chdir(ts->currDir);
01233 ts->chrootDone = 0;
01234 }
01235 if (fileMem)
01236 freeFileMemory(fileMem);
01237 if (oldH)
01238 headerFree(oldH);
01239 return rc;
01240 }