Main Page   Modules   Compound List   File List   Compound Members   File Members   Related Pages  

lib/install.c

Go to the documentation of this file.
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 /*@access Header@*/             /* XXX compared with NULL */
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 /*@owned@*/ const char ** names;
00036 /*@owned@*/ const char ** cpioNames;
00037 /*@owned@*/ const char ** md5sums;
00038 /*@owned@*/ struct fileInfo * files;
00039 };
00040 
00041 struct fileInfo {
00042 /*@dependent@*/ const char * cpioPath;
00043 /*@dependent@*/ const char * relativePath;      /* relative to root */
00044 /*@dependent@*/ 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 /* XXX add more tags */
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 /*@only@*/ 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( /*@only@*/ 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 /* files should not be preallocated */
00141 static int assembleFileList(Header h, /*@out@*/ struct fileMemory ** memPtr,
00142          /*@out@*/ int * fileCountPtr, /*@out@*/ 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             /* turn off the suid bit */
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             /* turn off the sgid bit */
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 **) &times,
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  /* DYING */
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             /*@notreached@*/ 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                     /* Modified header will be rewritten. */
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                         /*@out@*/ 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         /* install all files */
00578         fileCount = 0;
00579     } else if (!fileCount) {
00580         /* no files to install */
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             /* XXX Can't do src rpm MD5 sum verification (yet). */
00605     /* XXX binary rpms always have RPMTAG_SOURCERPM, source rpms do not */
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     /* Retrieve type of payload compression. */
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;  /* XXX FIXME: Fclose with libio destroys errno */
00644     Fclose(cfd);
00645     headerFree(info.h);
00646 
00647     if (rc) {
00648         /* this would probably be a good place to check if disk space
00649            was used up - if so, we should return a different error */
00650         errno = saveerrno; /* XXX FIXME: Fclose with libio destroys errno */
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             /*@fallthrough@*/
00712         case URL_IS_FTP:
00713         case URL_IS_HTTP:
00714             /* XXX this will only create last component of directory path */
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             /*@fallthrough@*/
00743         case URL_IS_FTP:
00744         case URL_IS_HTTP:
00745             /* XXX this will only create last component of directory path */
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         /* we can't remap v1 packages */
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             /* find the spec file by name */
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         /* This logic doesn't work if realSpecDir and realSourceDir are on
00831            different filesystems, but we only do this on v1 source packages
00832            so I don't really care much. */
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 /*@obserever@*/ 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     /*@notreached@*/
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;          /* strip at least first / for cpio */
00971     struct fileMemory *fileMem = NULL;
00972 
00973     /* XXX this looks broke, as libraries may need /sbin/ldconfig for example */
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         /* old format relocateable packages need the entire default
01004            prefix stripped to form the cpio list, while all other packages
01005            need the leading / stripped */
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         /* this loads all of the name services libraries, in case we
01043            don't have access to them in the chroot() */
01044         (void)getpwnam("root");
01045         endpwent();
01046 
01047         chdir("/");
01048         /*@-unrecog@*/ chroot(ts->rootDir); /*@=unrecog@*/
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             /* the file pointer for fd is pointing at the cpio archive */
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         /*@-unrecog@*/ chroot("."); /*@=unrecog@*/
01163         ts->chrootDone = 0;
01164         chdir(ts->currDir);
01165     }
01166 
01167 #ifdef  DYING
01168     trimChangelog(h);
01169 #endif
01170 
01171     /* if this package has already been installed, remove it from the database
01172        before adding the new one */
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         /* Run triggers this package sets off */
01209         if (runTriggers(ts, RPMSENSE_TRIGGERIN, h, 0)) {
01210             rc = 2;
01211             goto exit;
01212         }
01213 
01214         /*
01215          * Run triggers in this package which are set off by other packages in
01216          * the database.
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         /*@-unrecog@*/ chroot("."); /*@=unrecog@*/
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 }

Generated at Sun Apr 8 18:43:00 2001 for rpm by doxygen1.2.3 written by Dimitri van Heesch, © 1997-2000