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