- the big solv data change
[platform/upstream/libsolv.git] / src / solvable.c
1 /*
2  * Copyright (c) 2008, Novell Inc.
3  *
4  * This program is licensed under the BSD license, read LICENSE.BSD
5  * for further information
6  */
7
8 /*
9  * solvable.c
10  *
11  * set/retrieve data from solvables
12  */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <stdarg.h>
17 #include <unistd.h>
18 #include <string.h>
19
20 #include "pool.h"
21 #include "repo.h"
22 #include "util.h"
23
24 const char *
25 solvable2str(Pool *pool, Solvable *s)
26 {
27   const char *n, *e, *a;
28   char *p;
29   n = id2str(pool, s->name);
30   e = id2str(pool, s->evr);
31   a = id2str(pool, s->arch);
32   p = pool_alloctmpspace(pool, strlen(n) + strlen(e) + strlen(a) + 3);
33   sprintf(p, "%s-%s.%s", n, e, a);
34   return p;
35 }
36
37 Id
38 solvable_lookup_id(Solvable *s, Id keyname)
39 {
40   if (!s->repo)
41     return 0;
42   return repo_lookup_id(s->repo, s - s->repo->pool->solvables, keyname);
43 }
44
45 const char *
46 solvable_lookup_str(Solvable *s, Id keyname)
47 {
48   if (!s->repo)
49     return 0;
50   return repo_lookup_str(s->repo, s - s->repo->pool->solvables, keyname);
51 }
52
53 const char *
54 solvable_lookup_str_poollang(Solvable *s, Id keyname)
55 {
56   Pool *pool;
57   int i, cols;
58   const char *str;
59   Id *row;
60
61   if (!s->repo)
62     return 0;
63   pool = s->repo->pool;
64   if (!pool->nlanguages)
65     return solvable_lookup_str(s, keyname);
66   cols = pool->nlanguages + 1;
67   if (!pool->languagecache)
68     {
69       pool->languagecache = sat_calloc(cols * ID_NUM_INTERNAL, sizeof(Id));
70       pool->languagecacheother = 0;
71     }
72   if (keyname >= ID_NUM_INTERNAL)
73     {
74       row = pool->languagecache + ID_NUM_INTERNAL * cols;
75       for (i = 0; i < pool->languagecacheother; i++, row += cols)
76         if (*row == keyname)
77           break;
78       if (i >= pool->languagecacheother)
79         {
80           pool->languagecache = sat_realloc2(pool->languagecache, pool->languagecacheother + 1, cols * sizeof(Id));
81           pool->languagecacheother++;
82           row = pool->languagecache + cols * (ID_NUM_INTERNAL + pool->languagecacheother++);
83         }
84     }
85   else
86     row = pool->languagecache + keyname * cols;
87   row++;        /* skip keyname */
88   for (i = 0; i < pool->nlanguages; i++, row++)
89     {
90       if (!*row)
91         {
92           char *p;
93           const char *kn;
94
95           kn = id2str(pool, keyname);
96           p = sat_malloc(strlen(kn) + strlen(pool->languages[i]) + 2);
97           sprintf(p, "%s:%s", kn, pool->languages[i]);
98           *row = str2id(pool, p, 1);
99           sat_free(p);
100         }
101       str = solvable_lookup_str(s, *row);
102       if (str)
103         return str;
104     }
105   return solvable_lookup_str(s, keyname);
106 }
107
108 const char *
109 solvable_lookup_str_lang(Solvable *s, Id keyname, const char *lang)
110 {
111   if (s->repo)
112     {
113       const char *str;
114       Id id = pool_id2langid(s->repo->pool, keyname, lang, 0);
115       if (id && (str = solvable_lookup_str(s, id)) != 0)
116         return str;
117     }
118   return solvable_lookup_str(s, keyname);
119 }
120
121 unsigned int
122 solvable_lookup_num(Solvable *s, Id keyname, unsigned int notfound)
123 {
124   if (!s->repo)
125     return 0;
126   return repo_lookup_num(s->repo, s - s->repo->pool->solvables, keyname, notfound);
127 }
128
129 int
130 solvable_lookup_void(Solvable *s, Id keyname)
131 {
132   if (!s->repo)
133     return 0;
134   return repo_lookup_void(s->repo, s - s->repo->pool->solvables, keyname);
135 }
136
137 int
138 solvable_lookup_bool(Solvable *s, Id keyname)
139 {
140   Repo *repo = s->repo;
141   Pool *pool;
142   Repodata *data;
143   int i, j, n;
144
145   if (!repo)
146     return 0;
147   pool = repo->pool;
148   n = s - pool->solvables;
149   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
150     {
151       if (n < data->start || n >= data->end)
152         continue;
153       /* there are two ways of storing a bool, as num == 1 or void */
154       for (j = 1; j < data->nkeys; j++)
155         {
156           if (data->keys[j].name == keyname
157               && (data->keys[j].type == REPOKEY_TYPE_U32
158                   || data->keys[j].type == REPOKEY_TYPE_NUM
159                   || data->keys[j].type == REPOKEY_TYPE_CONSTANT
160                   || data->keys[j].type == REPOKEY_TYPE_VOID))
161             {
162               unsigned int value;
163               if (repodata_lookup_num(data, n, keyname, &value))
164                 return value == 1;
165               if (repodata_lookup_void(data, n, keyname))
166                 return 1;
167             }
168         }
169     }
170   return 0;
171 }
172
173 const unsigned char *
174 solvable_lookup_bin_checksum(Solvable *s, Id keyname, Id *typep)
175 {
176   Repo *repo = s->repo;
177
178   if (!repo)
179     {
180       *typep = 0;
181       return 0;
182     }
183   return repo_lookup_bin_checksum(repo, s - repo->pool->solvables, keyname, typep);
184 }
185
186 const char *
187 solvable_lookup_checksum(Solvable *s, Id keyname, Id *typep)
188 {
189   const unsigned char *chk = solvable_lookup_bin_checksum(s, keyname, typep);
190   /* we need the repodata just as a reference for a pool */
191   return chk ? repodata_chk2str(s->repo->repodata, *typep, chk) : 0;
192 }
193
194 char *
195 solvable_get_location(Solvable *s, unsigned int *medianrp)
196 {
197   Pool *pool;
198   int l = 0;
199   char *loc;
200   const char *mediadir, *mediafile;
201
202   *medianrp = 0;
203   if (!s->repo)
204     return 0;
205   pool = s->repo->pool;
206   *medianrp = solvable_lookup_num(s, SOLVABLE_MEDIANR, 1);
207   if (solvable_lookup_void(s, SOLVABLE_MEDIADIR))
208     mediadir = id2str(pool, s->arch);
209   else
210     mediadir = solvable_lookup_str(s, SOLVABLE_MEDIADIR);
211   if (mediadir)
212     l = strlen(mediadir) + 1;
213   if (solvable_lookup_void(s, SOLVABLE_MEDIAFILE))
214     {
215       const char *name, *evr, *arch;
216       name = id2str(pool, s->name);
217       evr = id2str(pool, s->evr);
218       arch = id2str(pool, s->arch);
219       /* name-evr.arch.rpm */
220       loc = pool_alloctmpspace(pool, l + strlen(name) + strlen(evr) + strlen(arch) + 7);
221       if (mediadir)
222         sprintf(loc, "%s/%s-%s.%s.rpm", mediadir, name, evr, arch);
223       else
224         sprintf(loc, "%s-%s.%s.rpm", name, evr, arch);
225     }
226   else
227     {
228       mediafile = solvable_lookup_str(s, SOLVABLE_MEDIAFILE);
229       if (!mediafile)
230         return 0;
231       loc = pool_alloctmpspace(pool, l + strlen(mediafile) + 1);
232       if (mediadir)
233         sprintf(loc, "%s/%s", mediadir, mediafile);
234       else
235         strcpy(loc, mediafile);
236     }
237   return loc;
238 }
239
240 /*****************************************************************************/
241
242 static inline Id dep2name(Pool *pool, Id dep)
243 {
244   while (ISRELDEP(dep))
245     {
246       Reldep *rd = rd = GETRELDEP(pool, dep);
247       dep = rd->name;
248     }
249   return dep;
250 }
251
252 static inline int providedbyinstalled(Pool *pool, Map *installed, Id dep)
253 {
254   Id p, pp;
255   FOR_PROVIDES(p, pp, dep)
256     {
257       if (p == SYSTEMSOLVABLE)
258         return -1;
259       if (MAPTST(installed, p))
260         return 1;
261     }
262   return 0;
263 }
264
265 /*
266  * solvable_trivial_installable_map - anwers is a solvable is installable
267  * without any other installs/deinstalls.
268  * The packages considered to be installed are provided via the
269  * installedmap bitmap. A additional "conflictsmap" bitmap providing
270  * information about the conflicts of the installed packages can be
271  * used for extra speed up. Provide a NULL pointer if you do not
272  * have this information.
273  * Both maps can be created with pool_create_state_maps() or
274  * solver_create_state_maps().
275  *
276  * returns:
277  * 1:  solvable is installable without any other package changes
278  * 0:  solvable is not installable
279  * -1: solvable is installable, but doesn't constrain any installed packages
280  */
281 int
282 solvable_trivial_installable_map(Solvable *s, Map *installedmap, Map *conflictsmap)
283 {
284   Pool *pool = s->repo->pool;
285   Solvable *s2;
286   Id p, pp, *dp;
287   Id *reqp, req;
288   Id *conp, con;
289   Id *obsp, obs;
290   int r, interesting = 0;
291
292   if (conflictsmap && MAPTST(conflictsmap, s - pool->solvables))
293     return 0;
294   if (s->requires)
295     {
296       reqp = s->repo->idarraydata + s->requires;
297       while ((req = *reqp++) != 0)
298         {
299           if (req == SOLVABLE_PREREQMARKER)
300             continue;
301           r = providedbyinstalled(pool, installedmap, req);
302           if (!r)
303             return 0;
304           if (r > 0)
305             interesting = 1;
306         }
307     }
308   if (s->conflicts)
309     {
310       conp = s->repo->idarraydata + s->conflicts;
311       while ((con = *conp++) != 0)
312         {
313           if (providedbyinstalled(pool, installedmap, con))
314             return 0;
315           if (!interesting && ISRELDEP(con))
316             {
317               con = dep2name(pool, con);
318               if (providedbyinstalled(pool, installedmap, con))
319                 interesting = 1;
320             }
321         }
322     }
323   if (s->repo)
324     {
325       Repo *installed = 0;
326       if (s->obsoletes && s->repo != installed)
327         {
328           obsp = s->repo->idarraydata + s->obsoletes;
329           while ((obs = *obsp++) != 0)
330             {
331               if (providedbyinstalled(pool, installedmap, obs))
332                 return 0;
333             }
334         }
335       if (s->repo != installed)
336         {
337           FOR_PROVIDES(p, pp, s->name)
338             {
339               s2 = pool->solvables + p;
340               if (s2->repo == installed && s2->name == s->name)
341                 return 0;
342             }
343         }
344     }
345   if (!conflictsmap)
346     {
347       int i;
348
349       p = s - pool->solvables;
350       for (i = 1; i < pool->nsolvables; i++)
351         {
352           if (!MAPTST(installedmap, i))
353             continue;
354           s2 = pool->solvables + i;
355           if (!s2->conflicts)
356             continue;
357           conp = s2->repo->idarraydata + s2->conflicts;
358           while ((con = *conp++) != 0)
359             {
360               dp = pool->whatprovidesdata + pool_whatprovides(pool, con);
361               for (; *dp; dp++)
362                 if (*dp == p)
363                   return 0;
364             }
365         }
366      }
367   return interesting ? 1 : -1;
368 }
369
370 /*
371  * different interface for solvable_trivial_installable_map, where
372  * the information about the installed packages is provided
373  * by a queue.
374  */
375 int
376 solvable_trivial_installable_queue(Solvable *s, Queue *installed)
377 {
378   Pool *pool = s->repo->pool;
379   int i;
380   Id p;
381   Map installedmap;
382   int r;
383
384   map_init(&installedmap, pool->nsolvables);
385   for (i = 0; i < installed->count; i++)
386     {
387       p = installed->elements[i];
388       if (p > 0)                /* makes it work with decisionq */
389         MAPSET(&installedmap, p);
390     }
391   r = solvable_trivial_installable_map(s, &installedmap, 0);
392   map_free(&installedmap);
393   return r;
394 }
395
396 /*
397  * different interface for solvable_trivial_installable_map, where
398  * the information about the installed packages is provided
399  * by a repo containing the installed solvables.
400  */
401 int
402 solvable_trivial_installable_repo(Solvable *s, Repo *installed)
403 {
404   Pool *pool = s->repo->pool;
405   Id p;
406   Solvable *s2;
407   Map installedmap;
408   int r;
409
410   map_init(&installedmap, pool->nsolvables);
411   FOR_REPO_SOLVABLES(installed, p, s2)
412     MAPSET(&installedmap, p);
413   r = solvable_trivial_installable_map(s, &installedmap, 0);
414   map_free(&installedmap);
415   return r;
416 }
417
418
419 /*****************************************************************************/
420
421 /*
422  * Create maps containing the state of each solvable. Input is a "installed" queue,
423  * it contains all solvable ids that are considered to be installed.
424  * 
425  * The created maps can be used for solvable_trivial_installable_map(),
426  * pool_calc_duchanges(), pool_calc_installsizechange().
427  *
428  */
429 void
430 pool_create_state_maps(Pool *pool, Queue *installed, Map *installedmap, Map *conflictsmap)
431 {
432   int i;
433   Solvable *s;
434   Id p, *dp;
435   Id *conp, con;
436
437   map_init(installedmap, pool->nsolvables);
438   if (conflictsmap)
439     map_init(conflictsmap, pool->nsolvables);
440   for (i = 0; i < installed->count; i++)
441     {
442       p = installed->elements[i];
443       if (p <= 0)       /* makes it work with decisionq */
444         continue;
445       MAPSET(installedmap, p);
446       if (!conflictsmap)
447         continue;
448       s = pool->solvables + p;
449       if (!s->conflicts)
450         continue;
451       conp = s->repo->idarraydata + s->conflicts;
452       while ((con = *conp++) != 0)
453         {
454           dp = pool->whatprovidesdata + pool_whatprovides(pool, con);
455           for (; *dp; dp++)
456             MAPSET(conflictsmap, *dp);
457         }
458     }
459 }
460
461 int
462 solvable_identical(Pool *pool, Solvable *s1, Solvable *s2)
463 {
464   unsigned int bt1, bt2;
465   Id rq1, rq2;
466   Id *reqp;
467
468   if (s1->name != s2->name)
469     return 0;
470   if (s1->arch != s2->arch)
471     return 0;
472   if (s1->evr != s2->evr)
473     return 0;
474   if (s1->vendor != s2->vendor)
475     return 0;
476
477   /* looking good, try some fancier stuff */
478   /* might also look up the package checksum here */
479   bt1 = solvable_lookup_num(s1, SOLVABLE_BUILDTIME, 0);
480   bt2 = solvable_lookup_num(s2, SOLVABLE_BUILDTIME, 0);
481   if (bt1 && bt2)
482     {
483       if (bt1 != bt2)
484         return 0;
485     }
486   else
487     {
488       /* look at requires in a last attempt to find recompiled packages */
489       rq1 = rq2 = 0;
490       if (s1->requires)
491         for (reqp = s1->repo->idarraydata + s1->requires; *reqp; reqp++)
492           rq1 ^= *reqp++;
493       if (s2->requires)
494         for (reqp = s2->repo->idarraydata + s2->requires; *reqp; reqp++)
495           rq2 ^= *reqp++;
496       if (rq1 != rq2)
497          return 0;
498     }
499   return 1;
500 }