Upload Tizen:Main source
[external/libsatsolver.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 #include "chksum.h"
24
25 const char *
26 pool_solvable2str(Pool *pool, Solvable *s)
27 {
28   const char *n, *e, *a;
29   char *p;
30   n = id2str(pool, s->name);
31   e = id2str(pool, s->evr);
32   a = id2str(pool, s->arch);
33   p = pool_alloctmpspace(pool, strlen(n) + strlen(e) + strlen(a) + 3);
34   sprintf(p, "%s-%s.%s", n, e, a);
35   return p;
36 }
37
38 Id
39 solvable_lookup_id(Solvable *s, Id keyname)
40 {
41   if (!s->repo)
42     return 0;
43   return repo_lookup_id(s->repo, s - s->repo->pool->solvables, keyname);
44 }
45
46 int
47 solvable_lookup_idarray(Solvable *s, Id keyname, Queue *q)
48 {
49   if (!s->repo)
50     {
51       queue_empty(q);
52       return 0;
53     }
54   return repo_lookup_idarray(s->repo, s - s->repo->pool->solvables, keyname, q);
55 }
56
57 const char *
58 solvable_lookup_str(Solvable *s, Id keyname)
59 {
60   if (!s->repo)
61     return 0;
62   return repo_lookup_str(s->repo, s - s->repo->pool->solvables, keyname);
63 }
64
65 static const char *
66 solvable_lookup_str_base(Solvable *s, Id keyname, Id basekeyname, int usebase)
67 {
68   Pool *pool;
69   const char *str, *basestr;
70   Id p, pp;
71   Solvable *s2;
72   int pass;
73
74   if (!s->repo)
75     return 0;
76   pool = s->repo->pool;
77   str = solvable_lookup_str(s, keyname);
78   if (str || keyname == basekeyname)
79     return str;
80   basestr = solvable_lookup_str(s, basekeyname);
81   if (!basestr)
82     return 0;
83   /* search for a solvable with same name and same base that has the
84    * translation */
85   if (!pool->whatprovides)
86     return usebase ? basestr : 0;
87   /* we do this in two passes, first same vendor, then all other vendors */
88   for (pass = 0; pass < 2; pass++)
89     {
90       FOR_PROVIDES(p, pp, s->name)
91         {
92           s2 = pool->solvables + p;
93           if (s2->name != s->name)
94             continue;
95           if ((s->vendor == s2->vendor) != (pass == 0))
96             continue;
97           str = solvable_lookup_str(s2, basekeyname);
98           if (!str || strcmp(str, basestr))
99             continue;
100           str = solvable_lookup_str(s2, keyname);
101           if (str)
102             return str;
103         }
104     }
105   return usebase ? basestr : 0;
106 }
107
108 const char *
109 solvable_lookup_str_poollang(Solvable *s, Id keyname)
110 {
111   Pool *pool;
112   int i, cols;
113   const char *str;
114   Id *row;
115
116   if (!s->repo)
117     return 0;
118   pool = s->repo->pool;
119   if (!pool->nlanguages)
120     return solvable_lookup_str(s, keyname);
121   cols = pool->nlanguages + 1;
122   if (!pool->languagecache)
123     {
124       pool->languagecache = sat_calloc(cols * ID_NUM_INTERNAL, sizeof(Id));
125       pool->languagecacheother = 0;
126     }
127   if (keyname >= ID_NUM_INTERNAL)
128     {
129       row = pool->languagecache + ID_NUM_INTERNAL * cols;
130       for (i = 0; i < pool->languagecacheother; i++, row += cols)
131         if (*row == keyname)
132           break;
133       if (i >= pool->languagecacheother)
134         {
135           pool->languagecache = sat_realloc2(pool->languagecache, pool->languagecacheother + 1, cols * sizeof(Id));
136           row = pool->languagecache + cols * (ID_NUM_INTERNAL + pool->languagecacheother++);
137           *row = keyname;
138         }
139     }
140   else
141     row = pool->languagecache + keyname * cols;
142   row++;        /* skip keyname */
143   for (i = 0; i < pool->nlanguages; i++, row++)
144     {
145       if (!*row)
146         *row = pool_id2langid(pool, keyname, pool->languages[i], 1);
147       str = solvable_lookup_str_base(s, *row, keyname, 0);
148       if (str)
149         return str;
150     }
151   return solvable_lookup_str(s, keyname);
152 }
153
154 const char *
155 solvable_lookup_str_lang(Solvable *s, Id keyname, const char *lang, int usebase)
156 {
157   if (s->repo)
158     {
159       Id id = pool_id2langid(s->repo->pool, keyname, lang, 0);
160       if (id)
161         return solvable_lookup_str_base(s, id, keyname, usebase);
162       if (!usebase)
163         return 0;
164     }
165   return solvable_lookup_str(s, keyname);
166 }
167
168 unsigned int
169 solvable_lookup_num(Solvable *s, Id keyname, unsigned int notfound)
170 {
171   if (!s->repo)
172     return notfound;
173   return repo_lookup_num(s->repo, s - s->repo->pool->solvables, keyname, notfound);
174 }
175
176 int
177 solvable_lookup_void(Solvable *s, Id keyname)
178 {
179   if (!s->repo)
180     return 0;
181   return repo_lookup_void(s->repo, s - s->repo->pool->solvables, keyname);
182 }
183
184 int
185 solvable_lookup_bool(Solvable *s, Id keyname)
186 {
187   if (!s->repo)
188     return 0;
189   /* historic nonsense: there are two ways of storing a bool, as num == 1 or void. test both. */
190   if (repo_lookup_type(s->repo, s - s->repo->pool->solvables, keyname) == REPOKEY_TYPE_VOID)
191     return 1;
192   return repo_lookup_num(s->repo, s - s->repo->pool->solvables, keyname, 0) == 1;
193 }
194
195 const unsigned char *
196 solvable_lookup_bin_checksum(Solvable *s, Id keyname, Id *typep)
197 {
198   Repo *repo = s->repo;
199
200   if (!repo)
201     {
202       *typep = 0;
203       return 0;
204     }
205   return repo_lookup_bin_checksum(repo, s - repo->pool->solvables, keyname, typep);
206 }
207
208 const char *
209 solvable_lookup_checksum(Solvable *s, Id keyname, Id *typep)
210 {
211   const unsigned char *chk = solvable_lookup_bin_checksum(s, keyname, typep);
212   return chk ? pool_bin2hex(s->repo->pool, chk, sat_chksum_len(*typep)) : 0;
213 }
214
215 static inline const char *
216 evrid2vrstr(Pool *pool, Id evrid)
217 {
218   const char *p, *evr = id2str(pool, evrid);
219   if (!evr)
220     return evr;
221   for (p = evr; *p >= '0' && *p <= '9'; p++)
222     ;
223   return p != evr && *p == ':' ? p + 1 : evr;
224 }
225
226 char *
227 solvable_get_location(Solvable *s, unsigned int *medianrp)
228 {
229   Pool *pool;
230   int l = 0;
231   char *loc;
232   const char *mediadir, *mediafile;
233
234   if (medianrp)
235     *medianrp = 0;
236   if (!s->repo)
237     return 0;
238   pool = s->repo->pool;
239   if (medianrp)
240     *medianrp = solvable_lookup_num(s, SOLVABLE_MEDIANR, 1);
241   if (solvable_lookup_void(s, SOLVABLE_MEDIADIR))
242     mediadir = id2str(pool, s->arch);
243   else
244     mediadir = solvable_lookup_str(s, SOLVABLE_MEDIADIR);
245   if (mediadir)
246     l = strlen(mediadir) + 1;
247   if (solvable_lookup_void(s, SOLVABLE_MEDIAFILE))
248     {
249       const char *name, *evr, *arch;
250       name = id2str(pool, s->name);
251       evr = evrid2vrstr(pool, s->evr);
252       arch = id2str(pool, s->arch);
253       /* name-vr.arch.rpm */
254       loc = pool_alloctmpspace(pool, l + strlen(name) + strlen(evr) + strlen(arch) + 7);
255       if (mediadir)
256         sprintf(loc, "%s/%s-%s.%s.rpm", mediadir, name, evr, arch);
257       else
258         sprintf(loc, "%s-%s.%s.rpm", name, evr, arch);
259     }
260   else
261     {
262       mediafile = solvable_lookup_str(s, SOLVABLE_MEDIAFILE);
263       if (!mediafile)
264         return 0;
265       loc = pool_alloctmpspace(pool, l + strlen(mediafile) + 1);
266       if (mediadir)
267         sprintf(loc, "%s/%s", mediadir, mediafile);
268       else
269         strcpy(loc, mediafile);
270     }
271   return loc;
272 }
273
274 /*****************************************************************************/
275
276 static inline Id dep2name(Pool *pool, Id dep)
277 {
278   while (ISRELDEP(dep))
279     {
280       Reldep *rd = rd = GETRELDEP(pool, dep);
281       dep = rd->name;
282     }
283   return dep;
284 }
285
286 static inline int providedbyinstalled(Pool *pool, Map *installed, Id dep)
287 {
288   Id p, pp;
289   FOR_PROVIDES(p, pp, dep)
290     {
291       if (p == SYSTEMSOLVABLE)
292         return -1;
293       if (MAPTST(installed, p))
294         return 1;
295     }
296   return 0;
297 }
298
299 /*
300  * solvable_trivial_installable_map - anwers is a solvable is installable
301  * without any other installs/deinstalls.
302  * The packages considered to be installed are provided via the
303  * installedmap bitmap. A additional "conflictsmap" bitmap providing
304  * information about the conflicts of the installed packages can be
305  * used for extra speed up. Provide a NULL pointer if you do not
306  * have this information.
307  * Both maps can be created with pool_create_state_maps() or
308  * solver_create_state_maps().
309  *
310  * returns:
311  * 1:  solvable is installable without any other package changes
312  * 0:  solvable is not installable
313  * -1: solvable is installable, but doesn't constrain any installed packages
314  */
315 int
316 solvable_trivial_installable_map(Solvable *s, Map *installedmap, Map *conflictsmap)
317 {
318   Pool *pool = s->repo->pool;
319   Solvable *s2;
320   Id p, pp, *dp;
321   Id *reqp, req;
322   Id *conp, con;
323   Id *obsp, obs;
324   int r, interesting = 0;
325
326   if (conflictsmap && MAPTST(conflictsmap, s - pool->solvables))
327     return 0;
328   if (s->requires)
329     {
330       reqp = s->repo->idarraydata + s->requires;
331       while ((req = *reqp++) != 0)
332         {
333           if (req == SOLVABLE_PREREQMARKER)
334             continue;
335           r = providedbyinstalled(pool, installedmap, req);
336           if (!r)
337             return 0;
338           if (r > 0)
339             interesting = 1;
340         }
341     }
342   if (s->conflicts)
343     {
344       conp = s->repo->idarraydata + s->conflicts;
345       while ((con = *conp++) != 0)
346         {
347           if (providedbyinstalled(pool, installedmap, con))
348             return 0;
349           if (!interesting && ISRELDEP(con))
350             {
351               con = dep2name(pool, con);
352               if (providedbyinstalled(pool, installedmap, con))
353                 interesting = 1;
354             }
355         }
356     }
357   if (s->repo)
358     {
359       Repo *installed = 0;
360       if (s->obsoletes && s->repo != installed)
361         {
362           obsp = s->repo->idarraydata + s->obsoletes;
363           while ((obs = *obsp++) != 0)
364             {
365               if (providedbyinstalled(pool, installedmap, obs))
366                 return 0;
367             }
368         }
369       if (s->repo != installed)
370         {
371           FOR_PROVIDES(p, pp, s->name)
372             {
373               s2 = pool->solvables + p;
374               if (s2->repo == installed && s2->name == s->name)
375                 return 0;
376             }
377         }
378     }
379   if (!conflictsmap)
380     {
381       int i;
382
383       p = s - pool->solvables;
384       for (i = 1; i < pool->nsolvables; i++)
385         {
386           if (!MAPTST(installedmap, i))
387             continue;
388           s2 = pool->solvables + i;
389           if (!s2->conflicts)
390             continue;
391           conp = s2->repo->idarraydata + s2->conflicts;
392           while ((con = *conp++) != 0)
393             {
394               dp = pool_whatprovides_ptr(pool, con);
395               for (; *dp; dp++)
396                 if (*dp == p)
397                   return 0;
398             }
399         }
400      }
401   return interesting ? 1 : -1;
402 }
403
404 /*
405  * different interface for solvable_trivial_installable_map, where
406  * the information about the installed packages is provided
407  * by a queue.
408  */
409 int
410 solvable_trivial_installable_queue(Solvable *s, Queue *installed)
411 {
412   Pool *pool = s->repo->pool;
413   int i;
414   Id p;
415   Map installedmap;
416   int r;
417
418   map_init(&installedmap, pool->nsolvables);
419   for (i = 0; i < installed->count; i++)
420     {
421       p = installed->elements[i];
422       if (p > 0)                /* makes it work with decisionq */
423         MAPSET(&installedmap, p);
424     }
425   r = solvable_trivial_installable_map(s, &installedmap, 0);
426   map_free(&installedmap);
427   return r;
428 }
429
430 /*
431  * different interface for solvable_trivial_installable_map, where
432  * the information about the installed packages is provided
433  * by a repo containing the installed solvables.
434  */
435 int
436 solvable_trivial_installable_repo(Solvable *s, Repo *installed)
437 {
438   Pool *pool = s->repo->pool;
439   Id p;
440   Solvable *s2;
441   Map installedmap;
442   int r;
443
444   map_init(&installedmap, pool->nsolvables);
445   FOR_REPO_SOLVABLES(installed, p, s2)
446     MAPSET(&installedmap, p);
447   r = solvable_trivial_installable_map(s, &installedmap, 0);
448   map_free(&installedmap);
449   return r;
450 }
451
452
453 /*****************************************************************************/
454
455 /*
456  * Create maps containing the state of each solvable. Input is a "installed" queue,
457  * it contains all solvable ids that are considered to be installed.
458  * 
459  * The created maps can be used for solvable_trivial_installable_map(),
460  * pool_calc_duchanges(), pool_calc_installsizechange().
461  *
462  */
463 void
464 pool_create_state_maps(Pool *pool, Queue *installed, Map *installedmap, Map *conflictsmap)
465 {
466   int i;
467   Solvable *s;
468   Id p, *dp;
469   Id *conp, con;
470
471   map_init(installedmap, pool->nsolvables);
472   if (conflictsmap)
473     map_init(conflictsmap, pool->nsolvables);
474   for (i = 0; i < installed->count; i++)
475     {
476       p = installed->elements[i];
477       if (p <= 0)       /* makes it work with decisionq */
478         continue;
479       MAPSET(installedmap, p);
480       if (!conflictsmap)
481         continue;
482       s = pool->solvables + p;
483       if (!s->conflicts)
484         continue;
485       conp = s->repo->idarraydata + s->conflicts;
486       while ((con = *conp++) != 0)
487         {
488           dp = pool_whatprovides_ptr(pool, con);
489           for (; *dp; dp++)
490             MAPSET(conflictsmap, *dp);
491         }
492     }
493 }
494
495 /* Tests if two solvables have identical content. Currently
496  * both solvables need to come from the same pool
497  */
498 int
499 solvable_identical(Solvable *s1, Solvable *s2)
500 {
501   unsigned int bt1, bt2;
502   Id rq1, rq2;
503   Id *reqp;
504
505   if (s1->name != s2->name)
506     return 0;
507   if (s1->arch != s2->arch)
508     return 0;
509   if (s1->evr != s2->evr)
510     return 0;
511   /* map missing vendor to empty string */
512   if ((s1->vendor ? s1->vendor : 1) != (s2->vendor ? s2->vendor : 1))
513     return 0;
514
515   /* looking good, try some fancier stuff */
516   /* might also look up the package checksum here */
517   bt1 = solvable_lookup_num(s1, SOLVABLE_BUILDTIME, 0);
518   bt2 = solvable_lookup_num(s2, SOLVABLE_BUILDTIME, 0);
519   if (bt1 && bt2)
520     {
521       if (bt1 != bt2)
522         return 0;
523     }
524   else
525     {
526       /* look at requires in a last attempt to find recompiled packages */
527       rq1 = rq2 = 0;
528       if (s1->requires)
529         for (reqp = s1->repo->idarraydata + s1->requires; *reqp; reqp++)
530           rq1 ^= *reqp;
531       if (s2->requires)
532         for (reqp = s2->repo->idarraydata + s2->requires; *reqp; reqp++)
533           rq2 ^= *reqp;
534       if (rq1 != rq2)
535          return 0;
536     }
537   return 1;
538 }
539
540 /* return the self provide dependency of a solvable */
541 Id
542 solvable_selfprovidedep(Solvable *s)
543 {
544   Pool *pool;
545   Reldep *rd;
546   Id prov, *provp;
547
548   if (!s->repo)
549     return s->name;
550   pool = s->repo->pool;
551   if (s->provides)
552     {
553       provp = s->repo->idarraydata + s->provides;
554       while ((prov = *provp++) != 0)
555         {
556           if (!ISRELDEP(prov))
557             continue;
558           rd = GETRELDEP(pool, prov);
559           if (rd->name == s->name && rd->evr == s->evr && rd->flags == REL_EQ)
560             return prov;
561         }
562     }
563   return rel2id(pool, s->name, s->evr, REL_EQ, 1);
564 }