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

lib/misc.c

Go to the documentation of this file.
00001 
00005 #include "system.h"
00006 
00007 static int _debug = 0;
00008 
00009 #include <rpmlib.h>
00010 #include <rpmurl.h>
00011 #include <rpmmacro.h>   /* XXX for rpmGetPath */
00012 
00013 #include "misc.h"
00014 #include "debug.h"
00015 
00016 /*@access Header@*/             /* XXX compared with NULL */
00017 /*@access FD_t@*/               /* XXX compared with NULL */
00018 
00019 char * RPMVERSION = VERSION;    /* just to put a marker in librpm.a */
00020 
00021 char ** splitString(const char * str, int length, char sep)
00022 {
00023     const char * source;
00024     char * s, * dest;
00025     char ** list;
00026     int i;
00027     int fields;
00028 
00029     s = xmalloc(length + 1);
00030 
00031     fields = 1;
00032     for (source = str, dest = s, i = 0; i < length; i++, source++, dest++) {
00033         *dest = *source;
00034         if (*dest == sep) fields++;
00035     }
00036 
00037     *dest = '\0';
00038 
00039     list = xmalloc(sizeof(char *) * (fields + 1));
00040 
00041     dest = s;
00042     list[0] = dest;
00043     i = 1;
00044     while (i < fields) {
00045         if (*dest == sep) {
00046             list[i++] = dest + 1;
00047             *dest = 0;
00048         }
00049         dest++;
00050     }
00051 
00052     list[i] = NULL;
00053 
00054     return list;
00055 }
00056 
00057 void freeSplitString(char ** list)
00058 {
00059     free(list[0]);
00060     free(list);
00061 }
00062 
00063 int rpmfileexists(const char * urlfn)
00064 {
00065     const char *fn;
00066     int urltype = urlPath(urlfn, &fn);
00067     struct stat buf;
00068 
00069     if (*fn == '\0') fn = "/";
00070     switch (urltype) {
00071     case URL_IS_FTP:    /* XXX WRONG WRONG WRONG */
00072     case URL_IS_HTTP:   /* XXX WRONG WRONG WRONG */
00073     case URL_IS_PATH:
00074     case URL_IS_UNKNOWN:
00075         if (Stat(fn, &buf)) {
00076             switch(errno) {
00077             case ENOENT:
00078             case EINVAL:
00079                 return 0;
00080             }
00081         }
00082         break;
00083     case URL_IS_DASH:
00084     default:
00085         return 0;
00086         /*@notreached@*/ break;
00087     }
00088 
00089     return 1;
00090 }
00091 
00092 /* compare alpha and numeric segments of two versions */
00093 /* return 1: a is newer than b */
00094 /*        0: a and b are the same version */
00095 /*       -1: b is newer than a */
00096 int rpmvercmp(const char * a, const char * b)
00097 {
00098     char oldch1, oldch2;
00099     char * str1, * str2;
00100     char * one, * two;
00101     int rc;
00102     int isnum;
00103 
00104     /* easy comparison to see if versions are identical */
00105     if (!strcmp(a, b)) return 0;
00106 
00107     str1 = alloca(strlen(a) + 1);
00108     str2 = alloca(strlen(b) + 1);
00109 
00110     strcpy(str1, a);
00111     strcpy(str2, b);
00112 
00113     one = str1;
00114     two = str2;
00115 
00116     /* loop through each version segment of str1 and str2 and compare them */
00117     while (*one && *two) {
00118         while (*one && !isalnum(*one)) one++;
00119         while (*two && !isalnum(*two)) two++;
00120 
00121         str1 = one;
00122         str2 = two;
00123 
00124         /* grab first completely alpha or completely numeric segment */
00125         /* leave one and two pointing to the start of the alpha or numeric */
00126         /* segment and walk str1 and str2 to end of segment */
00127         if (isdigit(*str1)) {
00128             while (*str1 && isdigit(*str1)) str1++;
00129             while (*str2 && isdigit(*str2)) str2++;
00130             isnum = 1;
00131         } else {
00132             while (*str1 && isalpha(*str1)) str1++;
00133             while (*str2 && isalpha(*str2)) str2++;
00134             isnum = 0;
00135         }
00136 
00137         /* save character at the end of the alpha or numeric segment */
00138         /* so that they can be restored after the comparison */
00139         oldch1 = *str1;
00140         *str1 = '\0';
00141         oldch2 = *str2;
00142         *str2 = '\0';
00143 
00144         /* take care of the case where the two version segments are */
00145         /* different types: one numeric and one alpha */
00146         if (one == str1) return -1;     /* arbitrary */
00147         if (two == str2) return -1;
00148 
00149         if (isnum) {
00150             /* this used to be done by converting the digit segments */
00151             /* to ints using atoi() - it's changed because long  */
00152             /* digit segments can overflow an int - this should fix that. */
00153 
00154             /* throw away any leading zeros - it's a number, right? */
00155             while (*one == '0') one++;
00156             while (*two == '0') two++;
00157 
00158             /* whichever number has more digits wins */
00159             if (strlen(one) > strlen(two)) return 1;
00160             if (strlen(two) > strlen(one)) return -1;
00161         }
00162 
00163         /* strcmp will return which one is greater - even if the two */
00164         /* segments are alpha or if they are numeric.  don't return  */
00165         /* if they are equal because there might be more segments to */
00166         /* compare */
00167         rc = strcmp(one, two);
00168         if (rc) return rc;
00169 
00170         /* restore character that was replaced by null above */
00171         *str1 = oldch1;
00172         one = str1;
00173         *str2 = oldch2;
00174         two = str2;
00175     }
00176 
00177     /* this catches the case where all numeric and alpha segments have */
00178     /* compared identically but the segment sepparating characters were */
00179     /* different */
00180     if ((!*one) && (!*two)) return 0;
00181 
00182     /* whichever version still has characters left over wins */
00183     if (!*one) return -1; else return 1;
00184 }
00185 
00186 int doputenv(const char *str)
00187 {
00188     char * a;
00189 
00190     /* FIXME: this leaks memory! */
00191 
00192     a = xmalloc(strlen(str) + 1);
00193     strcpy(a, str);
00194 
00195     return putenv(a);
00196 }
00197 
00198 int dosetenv(const char *name, const char *value, int overwrite)
00199 {
00200     int i;
00201     char * a;
00202 
00203     /* FIXME: this leaks memory! */
00204 
00205     if (!overwrite && getenv(name)) return 0;
00206 
00207     i = strlen(name) + strlen(value) + 2;
00208     a = xmalloc(i);
00209     if (!a) return 1;
00210 
00211     strcpy(a, name);
00212     strcat(a, "=");
00213     strcat(a, value);
00214 
00215     return putenv(a);
00216 }
00217 
00218 static int rpmMkpath(const char * path, mode_t mode, uid_t uid, gid_t gid)
00219 {
00220     char * d, * de;
00221     int created = 0;
00222     int rc;
00223 
00224     if (path == NULL)
00225         return -1;
00226     d = alloca(strlen(path)+2);
00227     de = stpcpy(d, path);
00228     de[1] = '\0';
00229     for (de = d; *de; de++) {
00230         struct stat st;
00231         char savec;
00232 
00233         while (*de && *de != '/') de++;
00234         savec = de[1];
00235         de[1] = '\0';
00236 
00237         rc = stat(d, &st);
00238         if (rc) {
00239             switch(errno) {
00240             default:
00241                 return errno;
00242                 /*@notreached@*/ break;
00243             case ENOENT:
00244                 break;
00245             }
00246             rc = mkdir(d, mode);
00247             if (rc)
00248                 return errno;
00249             created = 1;
00250             if (!(uid == (uid_t) -1 && gid == (gid_t) -1)) {
00251                 rc = chown(d, uid, gid);
00252                 if (rc)
00253                     return errno;
00254             }
00255         } else if (!S_ISDIR(st.st_mode)) {
00256             return ENOTDIR;
00257         }
00258         de[1] = savec;
00259     }
00260     rc = 0;
00261     if (created)
00262         rpmMessage(RPMMESS_WARNING, "created %%_tmppath directory %s\n", path);
00263     return rc;
00264 }
00265 
00266 int makeTempFile(const char * prefix, const char ** fnptr, FD_t * fdptr)
00267 {
00268     const char * tpmacro = "%{?_tmppath:%{_tmppath}}%{!?_tmppath:/var/tmp}";
00269     const char * tempfn = NULL;
00270     const char * tfn = NULL;
00271     static int _initialized = 0;
00272     int temput;
00273     FD_t fd = NULL;
00274     int ran;
00275 
00276     if (!prefix) prefix = "";
00277 
00278     /* Create the temp directory if it doesn't already exist. */
00279     if (!_initialized) {
00280         _initialized = 1;
00281         tempfn = rpmGenPath(prefix, tpmacro, NULL);
00282         if (rpmMkpath(tempfn, 0755, (uid_t) -1, (gid_t) -1))
00283             goto errxit;
00284     }
00285 
00286     /* XXX should probably use mkstemp here */
00287     srand(time(NULL));
00288     ran = rand() % 100000;
00289 
00290     /* maybe this should use link/stat? */
00291 
00292     do {
00293         char tfnbuf[64];
00294 #ifndef NOTYET
00295         sprintf(tfnbuf, "rpm-tmp.%d", ran++);
00296         if (tempfn)     free((void *)tempfn);
00297         tempfn = rpmGenPath(prefix, tpmacro, tfnbuf);
00298 #else
00299         strcpy(tfnbuf, "rpm-tmp.XXXXXX");
00300         if (tempfn)     free((void *)tempfn);
00301         tempfn = rpmGenPath(prefix, tpmacro, mktemp(tfnbuf));
00302 #endif
00303 
00304         temput = urlPath(tempfn, &tfn);
00305         if (*tfn == '\0') goto errxit;
00306 
00307         switch (temput) {
00308         case URL_IS_HTTP:
00309         case URL_IS_DASH:
00310             goto errxit;
00311             /*@notreached@*/ break;
00312         default:
00313             break;
00314         }
00315 
00316         fd = Fopen(tempfn, "w+x.ufdio");
00317         /* XXX FIXME: errno may not be correct for ufdio */
00318     } while ((fd == NULL || Ferror(fd)) && errno == EEXIST);
00319 
00320     if (fd == NULL || Ferror(fd))
00321         goto errxit;
00322 
00323     switch(temput) {
00324         struct stat sb, sb2;
00325     case URL_IS_PATH:
00326     case URL_IS_UNKNOWN:
00327         if (!stat(tfn, &sb) && S_ISLNK(sb.st_mode)) {
00328             rpmError(RPMERR_SCRIPT, _("error creating temporary file %s\n"), tfn);
00329             goto errxit;
00330         }
00331 
00332         if (sb.st_nlink != 1) {
00333             rpmError(RPMERR_SCRIPT, _("error creating temporary file %s\n"), tfn);
00334             goto errxit;
00335         }
00336 
00337         if (fstat(Fileno(fd), &sb2) == 0) {
00338             if (sb2.st_ino != sb.st_ino || sb2.st_dev != sb.st_dev) {
00339                 rpmError(RPMERR_SCRIPT, _("error creating temporary file %s\n"), tfn);
00340                 goto errxit;
00341             }
00342         }
00343         break;
00344     default:
00345         break;
00346     }
00347 
00348     if (fnptr)
00349         *fnptr = tempfn;
00350     else if (tempfn) {
00351         free((void *)tempfn);
00352         tempfn = NULL;
00353     }
00354     *fdptr = fd;
00355 
00356     return 0;
00357 
00358 errxit:
00359     if (tempfn) free((void *)tempfn);
00360     if (fd) Fclose(fd);
00361     return 1;
00362 }
00363 
00364 char * currentDirectory(void)
00365 {
00366     int currDirLen;
00367     char * currDir;
00368 
00369     currDirLen = 50;
00370     currDir = xmalloc(currDirLen);
00371     while (!getcwd(currDir, currDirLen) && errno == ERANGE) {
00372         currDirLen += 50;
00373         currDir = xrealloc(currDir, currDirLen);
00374     }
00375 
00376     return currDir;
00377 }
00378 
00379 int _noDirTokens = 0;
00380 
00381 static int dncmp(const void * a, const void * b)
00382 {
00383     const char *const * first = a;
00384     const char *const * second = b;
00385     return strcmp(*first, *second);
00386 }
00387 
00388 void compressFilelist(Header h)
00389 {
00390     char ** fileNames;
00391     const char ** dirNames;
00392     const char ** baseNames;
00393     int_32 * dirIndexes;
00394     int count;
00395     int i;
00396     int dirIndex = -1;
00397 
00398     /*
00399      * This assumes the file list is already sorted, and begins with a
00400      * single '/'. That assumption isn't critical, but it makes things go
00401      * a bit faster.
00402      */
00403 
00404     if (headerIsEntry(h, RPMTAG_DIRNAMES)) {
00405         headerRemoveEntry(h, RPMTAG_OLDFILENAMES);
00406         return;         /* Already converted. */
00407     }
00408 
00409     if (!headerGetEntry(h, RPMTAG_OLDFILENAMES, NULL,
00410                         (void **) &fileNames, &count))
00411         return;         /* no file list */
00412 
00413     dirNames = alloca(sizeof(*dirNames) * count);       /* worst case */
00414     baseNames = alloca(sizeof(*dirNames) * count);
00415     dirIndexes = alloca(sizeof(*dirIndexes) * count);
00416 
00417     if (fileNames[0][0] != '/') {
00418         /* HACK. Source RPM, so just do things differently */
00419         dirIndex = 0;
00420         dirNames[dirIndex] = "";
00421         for (i = 0; i < count; i++) {
00422             dirIndexes[i] = dirIndex;
00423             baseNames[i] = fileNames[i];
00424         }
00425         goto exit;
00426     }
00427 
00428     for (i = 0; i < count; i++) {
00429         const char ** needle;
00430         char *baseName = strrchr(fileNames[i], '/') + 1;
00431         char savechar;
00432         int len = baseName - fileNames[i];
00433 
00434         savechar = *baseName;
00435         *baseName = '\0';
00436         if (dirIndex < 0 ||
00437             (needle = bsearch(&fileNames[i], dirNames, dirIndex + 1, sizeof(dirNames[0]), dncmp)) == NULL) {
00438             char *s = alloca(len + 1);
00439             memcpy(s, fileNames[i], len + 1);
00440             s[len] = '\0';
00441             dirIndexes[i] = ++dirIndex;
00442             dirNames[dirIndex] = s;
00443         } else
00444             dirIndexes[i] = needle - dirNames;
00445 
00446         *baseName = savechar;
00447         baseNames[i] = baseName;
00448     }
00449 
00450 exit:
00451     headerAddEntry(h, RPMTAG_DIRINDEXES, RPM_INT32_TYPE,
00452                         dirIndexes, count);
00453     headerAddEntry(h, RPMTAG_BASENAMES, RPM_STRING_ARRAY_TYPE,
00454                         baseNames, count);
00455     headerAddEntry(h, RPMTAG_DIRNAMES, RPM_STRING_ARRAY_TYPE,
00456                         dirNames, dirIndex + 1);
00457 
00458     free((void *)fileNames);
00459 
00460     headerRemoveEntry(h, RPMTAG_OLDFILENAMES);
00461 }
00462 
00463 /*
00464  * This is pretty straight-forward. The only thing that even resembles a trick
00465  * is getting all of this into a single xmalloc'd block.
00466  */
00467 static void doBuildFileList(Header h, /*@out@*/ const char *** fileListPtr,
00468                             /*@out@*/ int * fileCountPtr, int baseNameTag,
00469                             int dirNameTag, int dirIndexesTag)
00470 {
00471     const char ** baseNames;
00472     const char ** dirNames;
00473     int * dirIndexes;
00474     int count;
00475     const char ** fileNames;
00476     int size;
00477     char * data;
00478     int i;
00479 
00480     if (!headerGetEntry(h, baseNameTag, NULL, (void **) &baseNames, &count)) {
00481         *fileListPtr = NULL;
00482         *fileCountPtr = 0;
00483         return;         /* no file list */
00484     }
00485 
00486     headerGetEntry(h, dirNameTag, NULL, (void **) &dirNames, NULL);
00487     headerGetEntry(h, dirIndexesTag, NULL, (void **) &dirIndexes, &count);
00488 
00489     size = sizeof(*fileNames) * count;
00490     for (i = 0; i < count; i++)
00491         size += strlen(baseNames[i]) + strlen(dirNames[dirIndexes[i]]) + 1;
00492 
00493     fileNames = xmalloc(size);
00494     data = ((char *) fileNames) + (sizeof(*fileNames) * count);
00495     for (i = 0; i < count; i++) {
00496         fileNames[i] = data;
00497         data = stpcpy( stpcpy(data, dirNames[dirIndexes[i]]), baseNames[i]);
00498         *data++ = '\0';
00499     }
00500     free((void *)baseNames);
00501     free((void *)dirNames);
00502 
00503     *fileListPtr = fileNames;
00504     *fileCountPtr = count;
00505 }
00506 
00507 void expandFilelist(Header h)
00508 {
00509     const char ** fileNames = NULL;
00510     int count = 0;
00511 
00512     if (!headerIsEntry(h, RPMTAG_OLDFILENAMES)) {
00513         doBuildFileList(h, &fileNames, &count, RPMTAG_BASENAMES,
00514                         RPMTAG_DIRNAMES, RPMTAG_DIRINDEXES);
00515         if (fileNames == NULL || count <= 0)
00516             return;
00517         headerAddEntry(h, RPMTAG_OLDFILENAMES, RPM_STRING_ARRAY_TYPE,
00518                         fileNames, count);
00519         free((void *)fileNames);
00520     }
00521 
00522     headerRemoveEntry(h, RPMTAG_DIRNAMES);
00523     headerRemoveEntry(h, RPMTAG_BASENAMES);
00524     headerRemoveEntry(h, RPMTAG_DIRINDEXES);
00525 }
00526 
00527 
00528 void rpmBuildFileList(Header h, const char *** fileListPtr, int * fileCountPtr)
00529 {
00530     doBuildFileList(h, fileListPtr, fileCountPtr, RPMTAG_BASENAMES,
00531                         RPMTAG_DIRNAMES, RPMTAG_DIRINDEXES);
00532 }
00533 
00534 void buildOrigFileList(Header h, const char *** fileListPtr, int * fileCountPtr)
00535 {
00536     doBuildFileList(h, fileListPtr, fileCountPtr, RPMTAG_ORIGBASENAMES,
00537                         RPMTAG_ORIGDIRNAMES, RPMTAG_ORIGDIRINDEXES);
00538 }
00539 
00540 /* glob_pattern_p() taken from bash
00541  * Copyright (C) 1985, 1988, 1989 Free Software Foundation, Inc.
00542  *
00543  * Return nonzero if PATTERN has any special globbing chars in it.
00544  */
00545 int myGlobPatternP (const char *patternURL)
00546 {
00547     const char *p;
00548     char c;
00549     int open = 0;
00550   
00551     (void) urlPath(patternURL, &p);
00552     while ((c = *p++) != '\0')
00553         switch (c) {
00554         case '?':
00555         case '*':
00556             return (1);
00557         case '[':      /* Only accept an open brace if there is a close */
00558             open++;    /* brace to match it.  Bracket expressions must be */
00559             continue;  /* complete, according to Posix.2 */
00560         case ']':
00561             if (open)
00562                 return (1);
00563             continue;      
00564         case '\\':
00565             if (*p++ == '\0')
00566                 return (0);
00567         }
00568 
00569     return (0);
00570 }
00571 
00572 static int glob_error(/*@unused@*/const char *foo, /*@unused@*/int bar)
00573 {
00574     return 1;
00575 }
00576 
00577 int rpmGlob(const char * patterns, int * argcPtr, const char *** argvPtr)
00578 {
00579     int ac = 0;
00580     const char ** av = NULL;
00581     int argc = 0;
00582     const char ** argv = NULL;
00583     const char * path;
00584     const char * globURL;
00585     char * globRoot = NULL;
00586     size_t maxb, nb;
00587     glob_t gl;
00588     int ut;
00589     int i, j;
00590     int rc;
00591 
00592     rc = poptParseArgvString(patterns, &ac, &av);
00593     if (rc)
00594         return rc;
00595 
00596     for (j = 0; j < ac; j++) {
00597         if (!myGlobPatternP(av[j])) {
00598             if (argc == 0)
00599                 argv = xmalloc((argc+2) * sizeof(*argv));
00600             else
00601                 argv = xrealloc(argv, (argc+1) * sizeof(*argv));
00602 if (_debug)
00603 fprintf(stderr, "*** rpmGlob argv[%d] \"%s\"\n", argc, av[j]);
00604             argv[argc++] = xstrdup(av[j]);
00605             continue;
00606         }
00607         
00608         gl.gl_pathc = 0;
00609         gl.gl_pathv = NULL;
00610         rc = Glob(av[j], 0, glob_error, &gl);
00611         if (rc)
00612             goto exit;
00613 
00614         /* XXX Prepend the URL leader for globs that have stripped it off */
00615         maxb = 0;
00616         for (i = 0; i < gl.gl_pathc; i++) {
00617             if ((nb = strlen(&(gl.gl_pathv[i][0]))) > maxb)
00618                 maxb = nb;
00619         }
00620         
00621         ut = urlPath(av[j], &path);
00622         nb = ((ut > URL_IS_DASH) ? (path - av[j]) : 0);
00623         maxb += nb;
00624         maxb += 1;
00625         globURL = globRoot = xmalloc(maxb);
00626 
00627         switch (ut) {
00628         case URL_IS_HTTP:
00629         case URL_IS_FTP:
00630         case URL_IS_PATH:
00631         case URL_IS_DASH:
00632             strncpy(globRoot, av[j], nb);
00633             break;
00634         case URL_IS_UNKNOWN:
00635             break;
00636         }
00637         globRoot += nb;
00638         *globRoot = '\0';
00639 if (_debug)
00640 fprintf(stderr, "*** GLOB maxb %d diskURL %d %*s globURL %p %s\n", (int)maxb, (int)nb, (int)nb, av[j], globURL, globURL);
00641         
00642         if (argc == 0)
00643             argv = xmalloc((gl.gl_pathc+1) * sizeof(*argv));
00644         else if (gl.gl_pathc > 0)
00645             argv = xrealloc(argv, (argc+gl.gl_pathc+1) * sizeof(*argv));
00646         for (i = 0; i < gl.gl_pathc; i++) {
00647             const char * globFile = &(gl.gl_pathv[i][0]);
00648             if (globRoot > globURL && globRoot[-1] == '/')
00649                 while (*globFile == '/') globFile++;
00650             strcpy(globRoot, globFile);
00651 if (_debug)
00652 fprintf(stderr, "*** rpmGlob argv[%d] \"%s\"\n", argc, globURL);
00653             argv[argc++] = xstrdup(globURL);
00654         }
00655         Globfree(&gl);
00656         free((void *)globURL);
00657     }
00658     if (argv != NULL && argc > 0) {
00659         argv[argc] = NULL;
00660         if (argvPtr)
00661             *argvPtr = argv;
00662         if (argcPtr)
00663             *argcPtr = argc;
00664         rc = 0;
00665     } else
00666         rc = 1;
00667 
00668 
00669 exit:
00670     if (av)
00671         free((void *)av);
00672     if ((rc || argvPtr == NULL) && argv) {
00673         for (i = 0; i < argc; i++)
00674             free((void *)argv[i]);
00675         free((void *)argv);
00676         argv = NULL;
00677     }
00678     return rc;
00679 }
00680 
00681 /*
00682  * XXX This is a "dressed" entry to headerGetEntry to do:
00683  *      1) DIRNAME/BASENAME/DIRINDICES -> FILENAMES tag conversions.
00684  *      2) i18n lookaside (if enabled).
00685  */
00686 int rpmHeaderGetEntry(Header h, int_32 tag, int_32 *type,
00687         void **p, int_32 *c)
00688 {
00689     switch (tag) {
00690     case RPMTAG_OLDFILENAMES:
00691     {   const char ** fl = NULL;
00692         int count;
00693         rpmBuildFileList(h, &fl, &count);
00694         if (count > 0) {
00695             *p = fl;
00696             if (c)      *c = count;
00697             if (type)   *type = RPM_STRING_ARRAY_TYPE;
00698             return 1;
00699         }
00700         if (c)  *c = 0;
00701         return 0;
00702     }   /*@notreached@*/ break;
00703 
00704     case RPMTAG_GROUP:
00705     case RPMTAG_DESCRIPTION:
00706     case RPMTAG_SUMMARY:
00707     {   char fmt[128];
00708         const char * msgstr;
00709         const char * errstr;
00710 
00711         fmt[0] = '\0';
00712         (void) stpcpy( stpcpy( stpcpy( fmt, "%{"), tagName(tag)), "}\n");
00713 
00714         /* XXX FIXME: memory leak. */
00715         msgstr = headerSprintf(h, fmt, rpmTagTable, rpmHeaderFormats, &errstr);
00716         if (msgstr) {
00717             *p = (void *) msgstr;
00718             if (type)   *type = RPM_STRING_TYPE;
00719             if (c)      *c = 1;
00720             return 1;
00721         } else {
00722             if (c)      *c = 0;
00723             return 0;
00724         }
00725     }   /*@notreached@*/ break;
00726 
00727     default:
00728         return headerGetEntry(h, tag, type, p, c);
00729         /*@notreached@*/ break;
00730     }
00731     /*@notreached@*/
00732 }
00733 
00734 /*
00735  * XXX Yet Another dressed entry to unify signature/header tag retrieval.
00736  */
00737 int rpmPackageGetEntry( /*@unused@*/ void *leadp, Header sigs, Header h,
00738         int_32 tag, int_32 *type, void **p, int_32 *c)
00739 {
00740     int_32 sigtag;
00741 
00742     switch (tag) {
00743     case RPMTAG_SIGSIZE:        sigtag = RPMSIGTAG_SIZE;        break;
00744     case RPMTAG_SIGLEMD5_1:     sigtag = RPMSIGTAG_LEMD5_1;     break;
00745     case RPMTAG_SIGPGP:         sigtag = RPMSIGTAG_PGP;         break;
00746     case RPMTAG_SIGLEMD5_2:     sigtag = RPMSIGTAG_LEMD5_2;     break;
00747     case RPMTAG_SIGMD5:         sigtag = RPMSIGTAG_MD5;         break;
00748     case RPMTAG_SIGGPG:         sigtag = RPMSIGTAG_GPG;         break;
00749     case RPMTAG_SIGPGP5:        sigtag = RPMSIGTAG_GPG;         break;
00750         
00751     default:
00752         return rpmHeaderGetEntry(h, tag, type, p, c);
00753         /*@notreached@*/ break;
00754     }
00755 
00756     if (headerIsEntry(h, tag))
00757         return rpmHeaderGetEntry(h, tag, type, p, c);
00758 
00759     if (sigs == NULL) {
00760         if (c)  *c = 0;
00761         return 0;
00762     }
00763 
00764     return headerGetEntry(sigs, sigtag, type, p, c);
00765 }
00766 
00767 /*
00768  * Up to rpm 3.0.4, packages implicitly provided their own name-version-release.
00769  * Retrofit an explicit "Provides: name = epoch:version-release.
00770  */
00771 void providePackageNVR(Header h)
00772 {
00773     const char *name, *version, *release;
00774     int_32 * epoch;
00775     const char *pEVR;
00776     char *p;
00777     int_32 pFlags = RPMSENSE_EQUAL;
00778     const char ** provides = NULL;
00779     const char ** providesEVR = NULL;
00780     int_32 * provideFlags = NULL;
00781     int providesCount;
00782     int i;
00783     int bingo = 1;
00784 
00785     /* Generate provides for this package name-version-release. */
00786     headerNVR(h, &name, &version, &release);
00787     pEVR = p = alloca(21 + strlen(version) + 1 + strlen(release) + 1);
00788     *p = '\0';
00789     if (headerGetEntry(h, RPMTAG_EPOCH, NULL, (void **) &epoch, NULL)) {
00790         sprintf(p, "%d:", *epoch);
00791         while (*p)
00792             p++;
00793     }
00794     (void) stpcpy( stpcpy( stpcpy(p, version) , "-") , release);
00795 
00796     /*
00797      * Rpm prior to 3.0.3 does not have versioned provides.
00798      * If no provides at all are available, we can just add.
00799      */
00800     if (!headerGetEntry(h, RPMTAG_PROVIDENAME, NULL,
00801                 (void **) &provides, &providesCount)) {
00802         goto exit;
00803     }
00804 
00805     /*
00806      * Otherwise, fill in entries on legacy packages.
00807      */
00808     if (!headerGetEntry(h, RPMTAG_PROVIDEVERSION, NULL,
00809                 (void **) &providesEVR, NULL)) {
00810         for (i = 0; i < providesCount; i++) {
00811             char * vdummy = "";
00812             int_32 fdummy = RPMSENSE_ANY;
00813             headerAddOrAppendEntry(h, RPMTAG_PROVIDEVERSION, RPM_STRING_ARRAY_TYPE,
00814                         &vdummy, 1);
00815             headerAddOrAppendEntry(h, RPMTAG_PROVIDEFLAGS, RPM_INT32_TYPE,
00816                         &fdummy, 1);
00817         }
00818         goto exit;
00819     }
00820 
00821     headerGetEntry(h, RPMTAG_PROVIDEFLAGS, NULL,
00822         (void **) &provideFlags, NULL);
00823 
00824     for (i = 0; i < providesCount; i++) {
00825         if (!(provideFlags[i] == RPMSENSE_EQUAL &&
00826             !strcmp(name, provides[i]) && !strcmp(pEVR, providesEVR[i])))
00827             continue;
00828         bingo = 0;
00829         break;
00830     }
00831 
00832 exit:
00833     if (provides) free((void *)provides);
00834     if (providesEVR) free((void *)providesEVR);
00835 
00836     if (bingo) {
00837         headerAddOrAppendEntry(h, RPMTAG_PROVIDENAME, RPM_STRING_ARRAY_TYPE,
00838                 &name, 1);
00839         headerAddOrAppendEntry(h, RPMTAG_PROVIDEFLAGS, RPM_INT32_TYPE,
00840                 &pFlags, 1);
00841         headerAddOrAppendEntry(h, RPMTAG_PROVIDEVERSION, RPM_STRING_ARRAY_TYPE,
00842                 &pEVR, 1);
00843     }
00844 }

Generated at Mon May 21 08:53:38 2001 for rpm by doxygen1.2.6 written by Dimitri van Heesch, © 1997-2001