solvable.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2008, Novell Inc.
00003  *
00004  * This program is licensed under the BSD license, read LICENSE.BSD
00005  * for further information
00006  */
00007 
00008 /*
00009  * solvable.c
00010  *
00011  * set/retrieve data from solvables
00012  */
00013 
00014 #include <stdio.h>
00015 #include <stdlib.h>
00016 #include <stdarg.h>
00017 #include <unistd.h>
00018 #include <string.h>
00019 
00020 #include "pool.h"
00021 #include "repo.h"
00022 #include "util.h"
00023 #include "chksum.h"
00024 
00025 const char *
00026 pool_solvable2str(Pool *pool, Solvable *s)
00027 {
00028   const char *n, *e, *a;
00029   char *p;
00030   n = id2str(pool, s->name);
00031   e = id2str(pool, s->evr);
00032   a = id2str(pool, s->arch);
00033   p = pool_alloctmpspace(pool, strlen(n) + strlen(e) + strlen(a) + 3);
00034   sprintf(p, "%s-%s.%s", n, e, a);
00035   return p;
00036 }
00037 
00038 Id
00039 solvable_lookup_id(Solvable *s, Id keyname)
00040 {
00041   if (!s->repo)
00042     return 0;
00043   return repo_lookup_id(s->repo, s - s->repo->pool->solvables, keyname);
00044 }
00045 
00046 int
00047 solvable_lookup_idarray(Solvable *s, Id keyname, Queue *q)
00048 {
00049   if (!s->repo)
00050     {
00051       queue_empty(q);
00052       return 0;
00053     }
00054   return repo_lookup_idarray(s->repo, s - s->repo->pool->solvables, keyname, q);
00055 }
00056 
00057 const char *
00058 solvable_lookup_str(Solvable *s, Id keyname)
00059 {
00060   if (!s->repo)
00061     return 0;
00062   return repo_lookup_str(s->repo, s - s->repo->pool->solvables, keyname);
00063 }
00064 
00065 static const char *
00066 solvable_lookup_str_base(Solvable *s, Id keyname, Id basekeyname, int usebase)
00067 {
00068   Pool *pool;
00069   const char *str, *basestr;
00070   Id p, pp;
00071   Solvable *s2;
00072   int pass;
00073 
00074   if (!s->repo)
00075     return 0;
00076   pool = s->repo->pool;
00077   str = solvable_lookup_str(s, keyname);
00078   if (str || keyname == basekeyname)
00079     return str;
00080   basestr = solvable_lookup_str(s, basekeyname);
00081   if (!basestr)
00082     return 0;
00083   /* search for a solvable with same name and same base that has the
00084    * translation */
00085   if (!pool->whatprovides)
00086     return usebase ? basestr : 0;
00087   /* we do this in two passes, first same vendor, then all other vendors */
00088   for (pass = 0; pass < 2; pass++)
00089     {
00090       FOR_PROVIDES(p, pp, s->name)
00091         {
00092           s2 = pool->solvables + p;
00093           if (s2->name != s->name)
00094             continue;
00095           if ((s->vendor == s2->vendor) != (pass == 0))
00096             continue;
00097           str = solvable_lookup_str(s2, basekeyname);
00098           if (!str || strcmp(str, basestr))
00099             continue;
00100           str = solvable_lookup_str(s2, keyname);
00101           if (str)
00102             return str;
00103         }
00104     }
00105   return usebase ? basestr : 0;
00106 }
00107 
00108 const char *
00109 solvable_lookup_str_poollang(Solvable *s, Id keyname)
00110 {
00111   Pool *pool;
00112   int i, cols;
00113   const char *str;
00114   Id *row;
00115 
00116   if (!s->repo)
00117     return 0;
00118   pool = s->repo->pool;
00119   if (!pool->nlanguages)
00120     return solvable_lookup_str(s, keyname);
00121   cols = pool->nlanguages + 1;
00122   if (!pool->languagecache)
00123     {
00124       pool->languagecache = sat_calloc(cols * ID_NUM_INTERNAL, sizeof(Id));
00125       pool->languagecacheother = 0;
00126     }
00127   if (keyname >= ID_NUM_INTERNAL)
00128     {
00129       row = pool->languagecache + ID_NUM_INTERNAL * cols;
00130       for (i = 0; i < pool->languagecacheother; i++, row += cols)
00131         if (*row == keyname)
00132           break;
00133       if (i >= pool->languagecacheother)
00134         {
00135           pool->languagecache = sat_realloc2(pool->languagecache, pool->languagecacheother + 1, cols * sizeof(Id));
00136           row = pool->languagecache + cols * (ID_NUM_INTERNAL + pool->languagecacheother++);
00137           *row = keyname;
00138         }
00139     }
00140   else
00141     row = pool->languagecache + keyname * cols;
00142   row++;        /* skip keyname */
00143   for (i = 0; i < pool->nlanguages; i++, row++)
00144     {
00145       if (!*row)
00146         *row = pool_id2langid(pool, keyname, pool->languages[i], 1);
00147       str = solvable_lookup_str_base(s, *row, keyname, 0);
00148       if (str)
00149         return str;
00150     }
00151   return solvable_lookup_str(s, keyname);
00152 }
00153 
00154 const char *
00155 solvable_lookup_str_lang(Solvable *s, Id keyname, const char *lang, int usebase)
00156 {
00157   if (s->repo)
00158     {
00159       Id id = pool_id2langid(s->repo->pool, keyname, lang, 0);
00160       if (id)
00161         return solvable_lookup_str_base(s, id, keyname, usebase);
00162       if (!usebase)
00163         return 0;
00164     }
00165   return solvable_lookup_str(s, keyname);
00166 }
00167 
00168 unsigned int
00169 solvable_lookup_num(Solvable *s, Id keyname, unsigned int notfound)
00170 {
00171   if (!s->repo)
00172     return notfound;
00173   return repo_lookup_num(s->repo, s - s->repo->pool->solvables, keyname, notfound);
00174 }
00175 
00176 int
00177 solvable_lookup_void(Solvable *s, Id keyname)
00178 {
00179   if (!s->repo)
00180     return 0;
00181   return repo_lookup_void(s->repo, s - s->repo->pool->solvables, keyname);
00182 }
00183 
00184 int
00185 solvable_lookup_bool(Solvable *s, Id keyname)
00186 {
00187   if (!s->repo)
00188     return 0;
00189   /* historic nonsense: there are two ways of storing a bool, as num == 1 or void. test both. */
00190   if (repo_lookup_type(s->repo, s - s->repo->pool->solvables, keyname) == REPOKEY_TYPE_VOID)
00191     return 1;
00192   return repo_lookup_num(s->repo, s - s->repo->pool->solvables, keyname, 0) == 1;
00193 }
00194 
00195 const unsigned char *
00196 solvable_lookup_bin_checksum(Solvable *s, Id keyname, Id *typep)
00197 {
00198   Repo *repo = s->repo;
00199 
00200   if (!repo)
00201     {
00202       *typep = 0;
00203       return 0;
00204     }
00205   return repo_lookup_bin_checksum(repo, s - repo->pool->solvables, keyname, typep);
00206 }
00207 
00208 const char *
00209 solvable_lookup_checksum(Solvable *s, Id keyname, Id *typep)
00210 {
00211   const unsigned char *chk = solvable_lookup_bin_checksum(s, keyname, typep);
00212   return chk ? pool_bin2hex(s->repo->pool, chk, sat_chksum_len(*typep)) : 0;
00213 }
00214 
00215 static inline const char *
00216 evrid2vrstr(Pool *pool, Id evrid)
00217 {
00218   const char *p, *evr = id2str(pool, evrid);
00219   if (!evr)
00220     return evr;
00221   for (p = evr; *p >= '0' && *p <= '9'; p++)
00222     ;
00223   return p != evr && *p == ':' ? p + 1 : evr;
00224 }
00225 
00226 char *
00227 solvable_get_location(Solvable *s, unsigned int *medianrp)
00228 {
00229   Pool *pool;
00230   int l = 0;
00231   char *loc;
00232   const char *mediadir, *mediafile;
00233 
00234   if (medianrp)
00235     *medianrp = 0;
00236   if (!s->repo)
00237     return 0;
00238   pool = s->repo->pool;
00239   if (medianrp)
00240     *medianrp = solvable_lookup_num(s, SOLVABLE_MEDIANR, 1);
00241   if (solvable_lookup_void(s, SOLVABLE_MEDIADIR))
00242     mediadir = id2str(pool, s->arch);
00243   else
00244     mediadir = solvable_lookup_str(s, SOLVABLE_MEDIADIR);
00245   if (mediadir)
00246     l = strlen(mediadir) + 1;
00247   if (solvable_lookup_void(s, SOLVABLE_MEDIAFILE))
00248     {
00249       const char *name, *evr, *arch;
00250       name = id2str(pool, s->name);
00251       evr = evrid2vrstr(pool, s->evr);
00252       arch = id2str(pool, s->arch);
00253       /* name-vr.arch.rpm */
00254       loc = pool_alloctmpspace(pool, l + strlen(name) + strlen(evr) + strlen(arch) + 7);
00255       if (mediadir)
00256         sprintf(loc, "%s/%s-%s.%s.rpm", mediadir, name, evr, arch);
00257       else
00258         sprintf(loc, "%s-%s.%s.rpm", name, evr, arch);
00259     }
00260   else
00261     {
00262       mediafile = solvable_lookup_str(s, SOLVABLE_MEDIAFILE);
00263       if (!mediafile)
00264         return 0;
00265       loc = pool_alloctmpspace(pool, l + strlen(mediafile) + 1);
00266       if (mediadir)
00267         sprintf(loc, "%s/%s", mediadir, mediafile);
00268       else
00269         strcpy(loc, mediafile);
00270     }
00271   return loc;
00272 }
00273 
00274 /*****************************************************************************/
00275 
00276 static inline Id dep2name(Pool *pool, Id dep)
00277 {
00278   while (ISRELDEP(dep))
00279     {
00280       Reldep *rd = rd = GETRELDEP(pool, dep);
00281       dep = rd->name;
00282     }
00283   return dep;
00284 }
00285 
00286 static inline int providedbyinstalled(Pool *pool, Map *installed, Id dep)
00287 {
00288   Id p, pp;
00289   FOR_PROVIDES(p, pp, dep)
00290     {
00291       if (p == SYSTEMSOLVABLE)
00292         return -1;
00293       if (MAPTST(installed, p))
00294         return 1;
00295     }
00296   return 0;
00297 }
00298 
00299 /*
00300  * solvable_trivial_installable_map - anwers is a solvable is installable
00301  * without any other installs/deinstalls.
00302  * The packages considered to be installed are provided via the
00303  * installedmap bitmap. A additional "conflictsmap" bitmap providing
00304  * information about the conflicts of the installed packages can be
00305  * used for extra speed up. Provide a NULL pointer if you do not
00306  * have this information.
00307  * Both maps can be created with pool_create_state_maps() or
00308  * solver_create_state_maps().
00309  *
00310  * returns:
00311  * 1:  solvable is installable without any other package changes
00312  * 0:  solvable is not installable
00313  * -1: solvable is installable, but doesn't constrain any installed packages
00314  */
00315 int
00316 solvable_trivial_installable_map(Solvable *s, Map *installedmap, Map *conflictsmap)
00317 {
00318   Pool *pool = s->repo->pool;
00319   Solvable *s2;
00320   Id p, pp, *dp;
00321   Id *reqp, req;
00322   Id *conp, con;
00323   Id *obsp, obs;
00324   int r, interesting = 0;
00325 
00326   if (conflictsmap && MAPTST(conflictsmap, s - pool->solvables))
00327     return 0;
00328   if (s->requires)
00329     {
00330       reqp = s->repo->idarraydata + s->requires;
00331       while ((req = *reqp++) != 0)
00332         {
00333           if (req == SOLVABLE_PREREQMARKER)
00334             continue;
00335           r = providedbyinstalled(pool, installedmap, req);
00336           if (!r)
00337             return 0;
00338           if (r > 0)
00339             interesting = 1;
00340         }
00341     }
00342   if (s->conflicts)
00343     {
00344       conp = s->repo->idarraydata + s->conflicts;
00345       while ((con = *conp++) != 0)
00346         {
00347           if (providedbyinstalled(pool, installedmap, con))
00348             return 0;
00349           if (!interesting && ISRELDEP(con))
00350             {
00351               con = dep2name(pool, con);
00352               if (providedbyinstalled(pool, installedmap, con))
00353                 interesting = 1;
00354             }
00355         }
00356     }
00357   if (s->repo)
00358     {
00359       Repo *installed = 0;
00360       if (s->obsoletes && s->repo != installed)
00361         {
00362           obsp = s->repo->idarraydata + s->obsoletes;
00363           while ((obs = *obsp++) != 0)
00364             {
00365               if (providedbyinstalled(pool, installedmap, obs))
00366                 return 0;
00367             }
00368         }
00369       if (s->repo != installed)
00370         {
00371           FOR_PROVIDES(p, pp, s->name)
00372             {
00373               s2 = pool->solvables + p;
00374               if (s2->repo == installed && s2->name == s->name)
00375                 return 0;
00376             }
00377         }
00378     }
00379   if (!conflictsmap)
00380     {
00381       int i;
00382 
00383       p = s - pool->solvables;
00384       for (i = 1; i < pool->nsolvables; i++)
00385         {
00386           if (!MAPTST(installedmap, i))
00387             continue;
00388           s2 = pool->solvables + i;
00389           if (!s2->conflicts)
00390             continue;
00391           conp = s2->repo->idarraydata + s2->conflicts;
00392           while ((con = *conp++) != 0)
00393             {
00394               dp = pool_whatprovides_ptr(pool, con);
00395               for (; *dp; dp++)
00396                 if (*dp == p)
00397                   return 0;
00398             }
00399         }
00400      }
00401   return interesting ? 1 : -1;
00402 }
00403 
00404 /*
00405  * different interface for solvable_trivial_installable_map, where
00406  * the information about the installed packages is provided
00407  * by a queue.
00408  */
00409 int
00410 solvable_trivial_installable_queue(Solvable *s, Queue *installed)
00411 {
00412   Pool *pool = s->repo->pool;
00413   int i;
00414   Id p;
00415   Map installedmap;
00416   int r;
00417 
00418   map_init(&installedmap, pool->nsolvables);
00419   for (i = 0; i < installed->count; i++)
00420     {
00421       p = installed->elements[i];
00422       if (p > 0)                /* makes it work with decisionq */
00423         MAPSET(&installedmap, p);
00424     }
00425   r = solvable_trivial_installable_map(s, &installedmap, 0);
00426   map_free(&installedmap);
00427   return r;
00428 }
00429 
00430 /*
00431  * different interface for solvable_trivial_installable_map, where
00432  * the information about the installed packages is provided
00433  * by a repo containing the installed solvables.
00434  */
00435 int
00436 solvable_trivial_installable_repo(Solvable *s, Repo *installed)
00437 {
00438   Pool *pool = s->repo->pool;
00439   Id p;
00440   Solvable *s2;
00441   Map installedmap;
00442   int r;
00443 
00444   map_init(&installedmap, pool->nsolvables);
00445   FOR_REPO_SOLVABLES(installed, p, s2)
00446     MAPSET(&installedmap, p);
00447   r = solvable_trivial_installable_map(s, &installedmap, 0);
00448   map_free(&installedmap);
00449   return r;
00450 }
00451 
00452 
00453 /*****************************************************************************/
00454 
00455 /*
00456  * Create maps containing the state of each solvable. Input is a "installed" queue,
00457  * it contains all solvable ids that are considered to be installed.
00458  * 
00459  * The created maps can be used for solvable_trivial_installable_map(),
00460  * pool_calc_duchanges(), pool_calc_installsizechange().
00461  *
00462  */
00463 void
00464 pool_create_state_maps(Pool *pool, Queue *installed, Map *installedmap, Map *conflictsmap)
00465 {
00466   int i;
00467   Solvable *s;
00468   Id p, *dp;
00469   Id *conp, con;
00470 
00471   map_init(installedmap, pool->nsolvables);
00472   if (conflictsmap)
00473     map_init(conflictsmap, pool->nsolvables);
00474   for (i = 0; i < installed->count; i++)
00475     {
00476       p = installed->elements[i];
00477       if (p <= 0)       /* makes it work with decisionq */
00478         continue;
00479       MAPSET(installedmap, p);
00480       if (!conflictsmap)
00481         continue;
00482       s = pool->solvables + p;
00483       if (!s->conflicts)
00484         continue;
00485       conp = s->repo->idarraydata + s->conflicts;
00486       while ((con = *conp++) != 0)
00487         {
00488           dp = pool_whatprovides_ptr(pool, con);
00489           for (; *dp; dp++)
00490             MAPSET(conflictsmap, *dp);
00491         }
00492     }
00493 }
00494 
00495 /* Tests if two solvables have identical content. Currently
00496  * both solvables need to come from the same pool
00497  */
00498 int
00499 solvable_identical(Solvable *s1, Solvable *s2)
00500 {
00501   unsigned int bt1, bt2;
00502   Id rq1, rq2;
00503   Id *reqp;
00504 
00505   if (s1->name != s2->name)
00506     return 0;
00507   if (s1->arch != s2->arch)
00508     return 0;
00509   if (s1->evr != s2->evr)
00510     return 0;
00511   /* map missing vendor to empty string */
00512   if ((s1->vendor ? s1->vendor : 1) != (s2->vendor ? s2->vendor : 1))
00513     return 0;
00514 
00515   /* looking good, try some fancier stuff */
00516   /* might also look up the package checksum here */
00517   bt1 = solvable_lookup_num(s1, SOLVABLE_BUILDTIME, 0);
00518   bt2 = solvable_lookup_num(s2, SOLVABLE_BUILDTIME, 0);
00519   if (bt1 && bt2)
00520     {
00521       if (bt1 != bt2)
00522         return 0;
00523     }
00524   else
00525     {
00526       /* look at requires in a last attempt to find recompiled packages */
00527       rq1 = rq2 = 0;
00528       if (s1->requires)
00529         for (reqp = s1->repo->idarraydata + s1->requires; *reqp; reqp++)
00530           rq1 ^= *reqp;
00531       if (s2->requires)
00532         for (reqp = s2->repo->idarraydata + s2->requires; *reqp; reqp++)
00533           rq2 ^= *reqp;
00534       if (rq1 != rq2)
00535          return 0;
00536     }
00537   return 1;
00538 }
00539 
00540 /* return the self provide dependency of a solvable */
00541 Id
00542 solvable_selfprovidedep(Solvable *s)
00543 {
00544   Pool *pool;
00545   Reldep *rd;
00546   Id prov, *provp;
00547 
00548   if (!s->repo)
00549     return s->name;
00550   pool = s->repo->pool;
00551   if (s->provides)
00552     {
00553       provp = s->repo->idarraydata + s->provides;
00554       while ((prov = *provp++) != 0)
00555         {
00556           if (!ISRELDEP(prov))
00557             continue;
00558           rd = GETRELDEP(pool, prov);
00559           if (rd->name == s->name && rd->evr == s->evr && rd->flags == REL_EQ)
00560             return prov;
00561         }
00562     }
00563   return rel2id(pool, s->name, s->evr, REL_EQ, 1);
00564 }

Generated on Mon Dec 15 17:56:24 2014 for satsolver by  doxygen 1.5.6